make swfdec_as_object_mark() only mark if not marked yet
[swfdec.git] / swfdec / swfdec_interval.c
blob68fd8c91bfb9d1b3999dcb7337556c2c1ef053b1
1 /* Swfdec
2 * Copyright (C) 2007 Benjamin Otte <otte@gnome.org>
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301 USA
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
24 #include <stdlib.h>
25 #include <string.h>
27 #include "swfdec_interval.h"
28 #include "swfdec_as_context.h"
29 #include "swfdec_as_frame_internal.h"
30 #include "swfdec_as_function.h"
31 #include "swfdec_as_internal.h"
32 #include "swfdec_debug.h"
33 #include "swfdec_player_internal.h"
34 #include "swfdec_resource.h"
36 G_DEFINE_TYPE (SwfdecInterval, swfdec_interval, SWFDEC_TYPE_GC_OBJECT)
38 static void
39 swfdec_interval_mark (SwfdecGcObject *object)
41 guint i;
42 SwfdecInterval *interval = SWFDEC_INTERVAL (object);
44 swfdec_gc_object_mark (interval->sandbox);
45 if (interval->fun_name)
46 swfdec_as_string_mark (interval->fun_name);
47 for (i = 0; i < interval->n_args + 1; i++) {
48 swfdec_as_value_mark (&interval->args[i]);
51 SWFDEC_GC_OBJECT_CLASS (swfdec_interval_parent_class)->mark (object);
54 static void
55 swfdec_interval_dispose (GObject *object)
57 SwfdecInterval *interval = SWFDEC_INTERVAL (object);
58 SwfdecAsContext *cx = swfdec_gc_object_get_context (interval);
60 if (interval->args) {
61 swfdec_as_context_unuse_mem (cx,
62 (interval->n_args + 1) * sizeof (SwfdecAsValue));
63 g_slice_free1 ((interval->n_args + 1) * sizeof (SwfdecAsValue), interval->args);
64 interval->args = NULL;
65 interval->n_args = 0;
67 /* needed here when GC'ed by closing the player */
68 if (interval->timeout.callback != NULL) {
69 swfdec_player_remove_timeout (SWFDEC_PLAYER (cx), &interval->timeout);
70 interval->timeout.callback = NULL;
73 G_OBJECT_CLASS (swfdec_interval_parent_class)->dispose (object);
76 static void
77 swfdec_interval_class_init (SwfdecIntervalClass *klass)
79 GObjectClass *object_class = G_OBJECT_CLASS (klass);
80 SwfdecGcObjectClass *gc_class = SWFDEC_GC_OBJECT_CLASS (klass);
82 object_class->dispose = swfdec_interval_dispose;
84 gc_class->mark = swfdec_interval_mark;
87 static void
88 swfdec_interval_init (SwfdecInterval *array)
92 static void
93 swfdec_interval_trigger (SwfdecTimeout *timeout)
95 SwfdecAsValue ret;
96 SwfdecInterval *interval = SWFDEC_INTERVAL ((void *) (((guchar *) timeout)
97 - G_STRUCT_OFFSET (SwfdecInterval, timeout)));
98 SwfdecAsContext *context = swfdec_gc_object_get_context (interval);
99 SwfdecPlayer *player = SWFDEC_PLAYER (context);
101 if (interval->repeat) {
102 timeout->timestamp += SWFDEC_MSECS_TO_TICKS (interval->msecs);
103 swfdec_player_add_timeout (player, timeout);
104 } else {
105 player->priv->intervals = g_list_remove (player->priv->intervals, interval);
106 interval->timeout.callback = NULL;
108 swfdec_sandbox_use (interval->sandbox);
109 if (interval->fun_name) {
110 SwfdecAsObject *object = swfdec_as_value_to_object (context, &interval->args[0]);
111 if (object) {
112 swfdec_as_object_call (object,
113 interval->fun_name, interval->n_args, interval->args, &ret);
115 } else {
116 /* we check that the relay's type is correct upon adding the interval */
117 swfdec_as_function_call (SWFDEC_AS_FUNCTION (
118 SWFDEC_AS_VALUE_GET_OBJECT (&interval->args[0])->relay),
119 NULL, interval->n_args, &interval->args[1], &ret);
121 swfdec_sandbox_unuse (interval->sandbox);
124 static guint
125 swfdec_interval_new (SwfdecPlayer *player, guint msecs, gboolean repeat,
126 const SwfdecAsValue *src, const char *fun_name,
127 guint n_args, const SwfdecAsValue *args)
129 SwfdecAsContext *context;
130 SwfdecInterval *interval;
132 context = SWFDEC_AS_CONTEXT (player);
133 if (!swfdec_as_context_try_use_mem (context, (n_args + 1) * sizeof (SwfdecAsValue))) {
134 swfdec_as_context_abort (context,
135 "Too many arguments passed to setInterval/setTimeout");
136 return 0;
138 interval = g_object_new (SWFDEC_TYPE_INTERVAL, "context", context, NULL);
140 interval->id = ++player->priv->interval_id;
141 interval->sandbox = swfdec_sandbox_get (player);
142 interval->msecs = msecs;
143 interval->repeat = repeat;
144 interval->fun_name = fun_name;
145 interval->n_args = n_args;
146 interval->args = g_slice_alloc ((n_args + 1) * sizeof (SwfdecAsValue));
147 interval->args[0] = *src;
148 if (n_args)
149 memcpy (&interval->args[1], args, n_args * sizeof (SwfdecAsValue));
150 interval->timeout.timestamp = player->priv->time + SWFDEC_MSECS_TO_TICKS (interval->msecs);
151 interval->timeout.callback = swfdec_interval_trigger;
152 swfdec_player_add_timeout (player, &interval->timeout);
154 player->priv->intervals =
155 g_list_prepend (player->priv->intervals, interval);
157 return interval->id;
160 guint
161 swfdec_interval_new_function (SwfdecPlayer *player, guint msecs, gboolean repeat,
162 SwfdecAsFunction *fun, guint n_args, const SwfdecAsValue *args)
164 SwfdecAsValue val;
166 g_return_val_if_fail (SWFDEC_IS_PLAYER (player), 0);
167 g_return_val_if_fail (msecs > 0, 0);
168 g_return_val_if_fail (SWFDEC_IS_AS_FUNCTION (fun), 0);
169 g_return_val_if_fail (n_args == 0 || args != NULL, 0);
171 SWFDEC_AS_VALUE_SET_OBJECT (&val,
172 swfdec_as_relay_get_as_object (SWFDEC_AS_RELAY (fun)));
173 return swfdec_interval_new (player, msecs, repeat, &val, NULL, n_args, args);
176 guint
177 swfdec_interval_new_object (SwfdecPlayer *player, guint msecs, gboolean repeat,
178 const SwfdecAsValue *thisp, const char *fun_name,
179 guint n_args, const SwfdecAsValue *args)
181 g_return_val_if_fail (SWFDEC_IS_PLAYER (player), 0);
182 g_return_val_if_fail (msecs > 0, 0);
183 g_return_val_if_fail (thisp != NULL, 0);
184 g_return_val_if_fail (fun_name != NULL, 0);
185 g_return_val_if_fail (n_args == 0 || args != NULL, 0);
187 return swfdec_interval_new (player, msecs, repeat, thisp, fun_name, n_args, args);
190 void
191 swfdec_interval_remove (SwfdecPlayer *player, guint id)
193 GList *walk;
195 g_return_if_fail (SWFDEC_IS_PLAYER (player));
197 for (walk = player->priv->intervals; walk; walk = walk->next) {
198 SwfdecInterval *interval = walk->data;
199 if (interval->id != id)
200 continue;
202 player->priv->intervals = g_list_delete_link (player->priv->intervals, walk);
203 swfdec_player_remove_timeout (player, &interval->timeout);
204 interval->timeout.callback = NULL;
205 return;