COMPOSITE => MOVIE for Actor
[swfdec.git] / swfdec / swfdec_actor.c
bloba35b7bf93d1b45c902c11e49f216c0425c69ba5f
1 /* Swfdec
2 * Copyright (C) 2006-2008 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 "swfdec_actor.h"
25 #include "swfdec_as_internal.h"
26 #include "swfdec_as_strings.h"
27 #include "swfdec_debug.h"
28 #include "swfdec_button_movie.h"
29 #include "swfdec_player_internal.h"
30 #include "swfdec_resource.h"
31 #include "swfdec_sandbox.h"
32 #include "swfdec_sprite_movie.h"
35 G_DEFINE_ABSTRACT_TYPE (SwfdecActor, swfdec_actor, SWFDEC_TYPE_MOVIE)
37 static void
38 swfdec_actor_dispose (GObject *object)
40 SwfdecActor *actor = SWFDEC_ACTOR (object);
42 if (actor->events) {
43 swfdec_event_list_free (actor->events);
44 actor->events = NULL;
47 G_OBJECT_CLASS (swfdec_actor_parent_class)->dispose (object);
50 static gboolean
51 swfdec_actor_iterate_end (SwfdecActor *actor)
53 SwfdecMovie *movie = SWFDEC_MOVIE (actor);
55 return movie->parent == NULL ||
56 movie->state < SWFDEC_MOVIE_STATE_REMOVED;
59 static gboolean
60 swfdec_actor_mouse_events (SwfdecActor *actor)
62 SwfdecAsObject *object;
64 /* root movies don't get event */
65 if (SWFDEC_MOVIE (actor)->parent == NULL)
66 return FALSE;
67 /* look if we have a script that gets events */
68 if (actor->events && swfdec_event_list_has_mouse_events (actor->events))
69 return TRUE;
70 /* otherwise, require at least one of the custom script handlers */
71 object = SWFDEC_AS_OBJECT (actor);
72 if (swfdec_as_object_has_variable (object, SWFDEC_AS_STR_onRollOver) ||
73 swfdec_as_object_has_variable (object, SWFDEC_AS_STR_onRollOut) ||
74 swfdec_as_object_has_variable (object, SWFDEC_AS_STR_onDragOver) ||
75 swfdec_as_object_has_variable (object, SWFDEC_AS_STR_onDragOut) ||
76 swfdec_as_object_has_variable (object, SWFDEC_AS_STR_onPress) ||
77 swfdec_as_object_has_variable (object, SWFDEC_AS_STR_onRelease) ||
78 swfdec_as_object_has_variable (object, SWFDEC_AS_STR_onReleaseOutside))
79 return TRUE;
80 return FALSE;
83 static void
84 swfdec_actor_mouse_in (SwfdecActor *actor)
86 if (swfdec_player_is_mouse_pressed (SWFDEC_PLAYER (swfdec_gc_object_get_context (actor))))
87 swfdec_actor_queue_script (actor, SWFDEC_EVENT_DRAG_OVER);
88 else
89 swfdec_actor_queue_script (actor, SWFDEC_EVENT_ROLL_OVER);
92 static void
93 swfdec_actor_mouse_out (SwfdecActor *actor)
95 if (swfdec_player_is_mouse_pressed (SWFDEC_PLAYER (swfdec_gc_object_get_context (actor))))
96 swfdec_actor_queue_script (actor, SWFDEC_EVENT_DRAG_OUT);
97 else
98 swfdec_actor_queue_script (actor, SWFDEC_EVENT_ROLL_OUT);
101 static void
102 swfdec_actor_mouse_press (SwfdecActor *actor, guint button)
104 if (button != 0)
105 return;
106 swfdec_actor_queue_script (actor, SWFDEC_EVENT_PRESS);
109 static void
110 swfdec_actor_mouse_release (SwfdecActor *actor, guint button)
112 SwfdecPlayer *player;
114 if (button != 0)
115 return;
117 player = SWFDEC_PLAYER (swfdec_gc_object_get_context (actor));
118 if (player->priv->mouse_below == actor)
119 swfdec_actor_queue_script (actor, SWFDEC_EVENT_RELEASE);
120 else
121 swfdec_actor_queue_script (actor, SWFDEC_EVENT_RELEASE_OUTSIDE);
124 static void
125 swfdec_actor_mouse_move (SwfdecActor *actor, double x, double y)
127 /* nothing to do here, it's just there so we don't need to check for NULL */
130 static void
131 swfdec_actor_key_press (SwfdecActor *actor, guint keycode, guint character)
133 swfdec_actor_queue_script (actor, SWFDEC_EVENT_KEY_DOWN);
136 static void
137 swfdec_actor_key_release (SwfdecActor *actor, guint keycode, guint character)
139 swfdec_actor_queue_script (actor, SWFDEC_EVENT_KEY_UP);
142 static GObject *
143 swfdec_actor_constructor (GType type, guint n_construct_properties,
144 GObjectConstructParam *construct_properties)
146 SwfdecPlayerPrivate *priv;
147 GObject *object;
149 object = G_OBJECT_CLASS (swfdec_actor_parent_class)->constructor (type,
150 n_construct_properties, construct_properties);
152 priv = SWFDEC_PLAYER (swfdec_gc_object_get_context (object))->priv;
153 /* NB: adding to the movies list happens before swfdec_movie_initialize().
154 * swfdec_movie_initialize() does a gotoAndPlay(0) for Sprites which can
155 * cause new movies to be created (and added to this list).
157 priv->actors = g_list_prepend (priv->actors, object);
159 return object;
162 static void
163 swfdec_actor_class_init (SwfdecActorClass *klass)
165 GObjectClass *object_class = G_OBJECT_CLASS (klass);
167 object_class->constructor = swfdec_actor_constructor;
168 object_class->dispose = swfdec_actor_dispose;
170 klass->iterate_end = swfdec_actor_iterate_end;
171 klass->mouse_events = swfdec_actor_mouse_events;
172 klass->mouse_in = swfdec_actor_mouse_in;
173 klass->mouse_out = swfdec_actor_mouse_out;
174 klass->mouse_press = swfdec_actor_mouse_press;
175 klass->mouse_release = swfdec_actor_mouse_release;
176 klass->mouse_move = swfdec_actor_mouse_move;
177 klass->key_press = swfdec_actor_key_press;
178 klass->key_release = swfdec_actor_key_release;
181 static void
182 swfdec_actor_init (SwfdecActor *actor)
184 swfdec_sound_matrix_init_identity (&actor->sound_matrix);
187 static gboolean
188 swfdec_sprite_movie_set_constructor (SwfdecSpriteMovie *movie)
190 SwfdecMovie *mov = SWFDEC_MOVIE (movie);
191 SwfdecAsContext *context = swfdec_gc_object_get_context (movie);
192 SwfdecAsObject *constructor = NULL;
194 g_assert (mov->resource != NULL);
196 if (movie->sprite) {
197 const char *name;
199 name = swfdec_resource_get_export_name (mov->resource,
200 SWFDEC_CHARACTER (movie->sprite));
201 if (name != NULL) {
202 name = swfdec_as_context_get_string (context, name);
203 constructor = swfdec_player_get_export_class (SWFDEC_PLAYER (context),
204 name);
207 if (constructor == NULL) {
208 swfdec_sandbox_use (SWFDEC_MOVIE (movie)->resource->sandbox);
209 swfdec_as_object_set_constructor_by_name (SWFDEC_AS_OBJECT (movie),
210 SWFDEC_AS_STR_MovieClip, NULL);
211 swfdec_sandbox_unuse (SWFDEC_MOVIE (movie)->resource->sandbox);
212 return FALSE;
213 } else {
214 swfdec_as_object_set_constructor (SWFDEC_AS_OBJECT (movie), constructor);
215 return TRUE;
219 void
220 swfdec_actor_execute (SwfdecActor *actor, SwfdecEventType condition,
221 guint8 key)
223 SwfdecAsObject *thisp;
224 const char *name;
225 guint version;
226 gboolean need_constructor = FALSE;
228 g_return_if_fail (SWFDEC_IS_ACTOR (actor));
230 version = swfdec_movie_get_version (SWFDEC_MOVIE (actor));
232 if (SWFDEC_IS_BUTTON_MOVIE (actor)) {
233 /* these conditions don't exist for buttons */
234 if (condition == SWFDEC_EVENT_CONSTRUCT || condition < SWFDEC_EVENT_PRESS)
235 return;
236 thisp = SWFDEC_AS_OBJECT (SWFDEC_MOVIE (actor)->parent);
237 if (version <= 5) {
238 while (!SWFDEC_IS_SPRITE_MOVIE (thisp))
239 thisp = SWFDEC_AS_OBJECT (SWFDEC_MOVIE (thisp)->parent);
241 g_assert (thisp);
242 } else {
243 thisp = SWFDEC_AS_OBJECT (actor);
246 /* special cases */
247 if (condition == SWFDEC_EVENT_CONSTRUCT) {
248 if (version <= 5)
249 return;
250 need_constructor = swfdec_sprite_movie_set_constructor (SWFDEC_SPRITE_MOVIE (actor));
251 } else if (condition == SWFDEC_EVENT_ENTER) {
252 if (SWFDEC_MOVIE (actor)->state >= SWFDEC_MOVIE_STATE_REMOVED)
253 return;
254 } else if (condition == SWFDEC_EVENT_SCROLL || condition == SWFDEC_EVENT_CHANGED) {
255 SwfdecAsValue argv[2];
256 SwfdecMovie *movie = SWFDEC_MOVIE (actor);
258 if (condition == SWFDEC_EVENT_SCROLL)
259 SWFDEC_AS_VALUE_SET_STRING (&argv[0], SWFDEC_AS_STR_onScroller);
260 else
261 SWFDEC_AS_VALUE_SET_STRING (&argv[0], SWFDEC_AS_STR_onChanged);
262 SWFDEC_AS_VALUE_SET_MOVIE (&argv[1], movie);
263 swfdec_sandbox_use (movie->resource->sandbox);
264 swfdec_as_object_call (SWFDEC_AS_OBJECT (actor),
265 SWFDEC_AS_STR_broadcastMessage, 2, argv, NULL);
266 swfdec_sandbox_unuse (movie->resource->sandbox);
267 return;
270 swfdec_sandbox_use (SWFDEC_MOVIE (actor)->resource->sandbox);
271 if (actor->events) {
272 swfdec_event_list_execute (actor->events, thisp, condition, key);
274 /* FIXME: how do we compute the version correctly here? */
275 if (version > 5) {
276 name = swfdec_event_type_get_name (condition);
277 if (name != NULL) {
278 swfdec_as_object_call (SWFDEC_AS_OBJECT (actor), name, 0, NULL, NULL);
280 if (condition == SWFDEC_EVENT_CONSTRUCT && need_constructor)
281 swfdec_as_object_call (thisp, SWFDEC_AS_STR_constructor, 0, NULL, NULL);
283 swfdec_sandbox_unuse (SWFDEC_MOVIE (actor)->resource->sandbox);
287 * swfdec_actor_queue_script_with_key:
288 * @movie: a #SwfdecMovie
289 * @condition: the event that should happen
290 * @key: the key for this event
292 * Queues execution of all scripts associated with the given event and key.
294 void
295 swfdec_actor_queue_script_with_key (SwfdecActor *actor,
296 SwfdecEventType condition, guint8 key)
298 SwfdecPlayer *player;
299 guint importance;
301 g_return_if_fail (SWFDEC_IS_ACTOR (actor));
303 if (!SWFDEC_IS_SPRITE_MOVIE (actor) && !SWFDEC_IS_BUTTON_MOVIE (actor))
304 return;
305 /* can happen for mouse/keyboard events on the initial movie */
306 if (SWFDEC_MOVIE (actor)->resource->sandbox == NULL) {
307 SWFDEC_INFO ("movie %s not yet initialized, skipping event", SWFDEC_MOVIE (actor)->name);
308 return;
311 switch (condition) {
312 case SWFDEC_EVENT_INITIALIZE:
313 importance = SWFDEC_PLAYER_ACTION_QUEUE_INIT;
314 break;
315 case SWFDEC_EVENT_CONSTRUCT:
316 importance = SWFDEC_PLAYER_ACTION_QUEUE_CONSTRUCT;
317 break;
318 case SWFDEC_EVENT_LOAD:
319 case SWFDEC_EVENT_ENTER:
320 case SWFDEC_EVENT_UNLOAD:
321 case SWFDEC_EVENT_MOUSE_MOVE:
322 case SWFDEC_EVENT_MOUSE_DOWN:
323 case SWFDEC_EVENT_MOUSE_UP:
324 case SWFDEC_EVENT_KEY_UP:
325 case SWFDEC_EVENT_KEY_DOWN:
326 case SWFDEC_EVENT_DATA:
327 case SWFDEC_EVENT_PRESS:
328 case SWFDEC_EVENT_RELEASE:
329 case SWFDEC_EVENT_RELEASE_OUTSIDE:
330 case SWFDEC_EVENT_ROLL_OVER:
331 case SWFDEC_EVENT_ROLL_OUT:
332 case SWFDEC_EVENT_DRAG_OVER:
333 case SWFDEC_EVENT_DRAG_OUT:
334 case SWFDEC_EVENT_KEY_PRESS:
335 case SWFDEC_EVENT_CHANGED:
336 case SWFDEC_EVENT_SCROLL:
337 importance = SWFDEC_PLAYER_ACTION_QUEUE_NORMAL;
338 break;
339 default:
340 g_return_if_reached ();
343 player = SWFDEC_PLAYER (swfdec_gc_object_get_context (actor));
344 swfdec_player_add_action (player, actor, condition, key, importance);
348 * swfdec_actor_queue_script:
349 * @movie: a #SwfdecMovie
350 * @condition: the event that should happen
352 * Queues execution of all scripts associated with the given event.
354 void
355 swfdec_actor_queue_script (SwfdecActor *actor, SwfdecEventType condition)
357 swfdec_actor_queue_script_with_key (actor, condition, 0);
361 * swfdec_actor_get_mouse_events:
362 * @movie: a #SwfdecActor
364 * Checks if this actor should respond to mouse events.
366 * Returns: %TRUE if this movie can receive mouse events
368 gboolean
369 swfdec_actor_get_mouse_events (SwfdecActor *actor)
371 SwfdecActorClass *klass;
373 g_return_val_if_fail (SWFDEC_IS_ACTOR (actor), FALSE);
375 klass = SWFDEC_ACTOR_GET_CLASS (actor);
376 if (klass->mouse_events)
377 return klass->mouse_events (actor);
378 else
379 return FALSE;
382 gboolean
383 swfdec_actor_has_focusrect (SwfdecActor *actor)
385 g_return_val_if_fail (SWFDEC_IS_ACTOR (actor), FALSE);
387 if (!SWFDEC_IS_BUTTON_MOVIE (actor) &&
388 !SWFDEC_IS_SPRITE_MOVIE (actor))
389 return FALSE;
391 if (actor->focusrect == SWFDEC_FLASH_MAYBE) {
392 actor = SWFDEC_ACTOR (swfdec_movie_get_root (SWFDEC_MOVIE (actor)));
394 g_assert (actor->focusrect != SWFDEC_FLASH_MAYBE);
396 return actor->focusrect != SWFDEC_FLASH_NO;