2 * Copyright (C) 2006-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.
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
28 #include <liboil/liboil.h>
30 #include "swfdec_player_internal.h"
31 #include "swfdec_as_frame_internal.h"
32 #include "swfdec_as_internal.h"
33 #include "swfdec_as_strings.h"
34 #include "swfdec_audio_internal.h"
35 #include "swfdec_button_movie.h" /* for mouse cursor */
36 #include "swfdec_cache.h"
37 #include "swfdec_debug.h"
38 #include "swfdec_enums.h"
39 #include "swfdec_event.h"
40 #include "swfdec_flash_security.h"
41 #include "swfdec_initialize.h"
42 #include "swfdec_internal.h"
43 #include "swfdec_loader_internal.h"
44 #include "swfdec_marshal.h"
45 #include "swfdec_movie.h"
46 #include "swfdec_resource.h"
47 #include "swfdec_resource_request.h"
48 #include "swfdec_script_internal.h"
49 #include "swfdec_sprite_movie.h"
50 #include "swfdec_utils.h"
55 * SECTION:SwfdecPlayer
56 * @title: SwfdecPlayer
57 * @short_description: main playback object
59 * A #SwfdecPlayer is the main object used for playing back Flash files through
62 * A player interacts with the outside world in a multitude of ways. The most
63 * important ones are described below.
65 * Input is handled via the
66 * <link linkend="swfdec-SwfdecLoader">SwfdecLoader</link> class. A
67 * #SwfdecLoader is set on a new player using swfdec_player_set_loader().
69 * When the loader has provided enough data, you can start playing the file.
70 * This is done in steps by calling swfdec_player_advance() - preferrably as
71 * often as swfdec_player_get_next_event() indicates. Or you can provide user input
72 * to the player by calling for example swfdec_player_handle_mouse().
74 * You can use swfdec_player_render() to draw the current state of the player.
75 * After that, connect to the SwfdecPlayer::invalidate signal to be notified of
78 * Audio output is handled via the
79 * <link linkend="swfdec-SwfdecAudio">SwfdecAudio</link> class. One
80 * #SwfdecAudio object is created for every output using the
81 * SwfdecPlayer::audio-added signal.
87 * This is the base object used for playing Flash files.
91 * SECTION:Enumerations
92 * @title: Enumerations
93 * @short_description: enumerations used in Swfdec
95 * This file lists all of the enumerations used in various parts of Swfdec.
100 * @SWFDEC_MOUSE_CURSOR_NORMAL: a normal mouse cursor
101 * @SWFDEC_MOUSE_CURSOR_NONE: no mouse image
102 * @SWFDEC_MOUSE_CURSOR_TEXT: a mouse cursor suitable for text editing
103 * @SWFDEC_MOUSE_CURSOR_CLICK: a mouse cursor for clicking a hyperlink or a
106 * This enumeration describes the possible types for the SwfdecPlayer::mouse-cursor
112 * @SWFDEC_ALIGNMENT_TOP_LEFT: top left
113 * @SWFDEC_ALIGNMENT_TOP: top
114 * @SWFDEC_ALIGNMENT_TOP_RIGHT: top right
115 * @SWFDEC_ALIGNMENT_LEFT: left
116 * @SWFDEC_ALIGNMENT_CENTER: center
117 * @SWFDEC_ALIGNMENT_RIGHT: right
118 * @SWFDEC_ALIGNMENT_BOTTOM_LEFT: left
119 * @SWFDEC_ALIGNMENT_BOTTOM: bottom
120 * @SWFDEC_ALIGNMENT_BOTTOM_RIGHT: bottom right
122 * These are the possible values for the alignment of an unscaled movie.
127 * @SWFDEC_SCALE_SHOW_ALL: Show the whole content as large as possible
128 * @SWFDEC_SCALE_NO_BORDER: Fill the whole area, possibly cropping parts
129 * @SWFDEC_SCALE_EXACT_FIT: Fill the whole area, don't keep aspect ratio
130 * @SWFDEC_SCALE_NONE: Do not scale the movie at all
132 * Describes how the movie should be scaled if the given size doesn't equal the
138 * @SWFDEC_KEY_BACKSPACE: the backspace key
139 * @SWFDEC_KEY_TAB: the tab key
140 * @SWFDEC_KEY_CLEAR: the clear key
141 * @SWFDEC_KEY_ENTER: the enter key
142 * @SWFDEC_KEY_SHIFT: the shift key
143 * @SWFDEC_KEY_CONTROL: the control key
144 * @SWFDEC_KEY_ALT: the alt key
145 * @SWFDEC_KEY_CAPS_LOCK: the caps lock key
146 * @SWFDEC_KEY_ESCAPE: the escape key
147 * @SWFDEC_KEY_SPACE: the space key
148 * @SWFDEC_KEY_PAGE_UP: the page up key
149 * @SWFDEC_KEY_PAGE_DOWN: the page down key
150 * @SWFDEC_KEY_END: the end key
151 * @SWFDEC_KEY_HOME: the home key
152 * @SWFDEC_KEY_LEFT: the left key
153 * @SWFDEC_KEY_UP: the up key
154 * @SWFDEC_KEY_RIGHT: the right key
155 * @SWFDEC_KEY_DOWN: the down key
156 * @SWFDEC_KEY_INSERT: the insert key
157 * @SWFDEC_KEY_DELETE: the delete key
158 * @SWFDEC_KEY_HELP: the help key
159 * @SWFDEC_KEY_0: the 0 key
160 * @SWFDEC_KEY_1: the 1 key
161 * @SWFDEC_KEY_2: the 2 key
162 * @SWFDEC_KEY_3: the 3 key
163 * @SWFDEC_KEY_4: the 4 key
164 * @SWFDEC_KEY_5: the 5 key
165 * @SWFDEC_KEY_6: the 6 key
166 * @SWFDEC_KEY_7: the 7 key
167 * @SWFDEC_KEY_8: the 8 key
168 * @SWFDEC_KEY_9: the 9 key
169 * @SWFDEC_KEY_A: the ! key
170 * @SWFDEC_KEY_B: the B key
171 * @SWFDEC_KEY_C: the C key
172 * @SWFDEC_KEY_D: the D key
173 * @SWFDEC_KEY_E: the E key
174 * @SWFDEC_KEY_F: the F key
175 * @SWFDEC_KEY_G: the G key
176 * @SWFDEC_KEY_H: the H key
177 * @SWFDEC_KEY_I: the I key
178 * @SWFDEC_KEY_J: the J key
179 * @SWFDEC_KEY_K: the K key
180 * @SWFDEC_KEY_L: the L key
181 * @SWFDEC_KEY_M: the M key
182 * @SWFDEC_KEY_N: the N key
183 * @SWFDEC_KEY_O: the O key
184 * @SWFDEC_KEY_P: the P key
185 * @SWFDEC_KEY_Q: the Q key
186 * @SWFDEC_KEY_R: the R key
187 * @SWFDEC_KEY_S: the S key
188 * @SWFDEC_KEY_T: the T key
189 * @SWFDEC_KEY_U: the U key
190 * @SWFDEC_KEY_V: the V key
191 * @SWFDEC_KEY_W: the W key
192 * @SWFDEC_KEY_X: the X key
193 * @SWFDEC_KEY_Y: the Y key
194 * @SWFDEC_KEY_Z: the Z key
195 * @SWFDEC_KEY_NUMPAD_0: the 0 key on the numeric keypad
196 * @SWFDEC_KEY_NUMPAD_1: the 1 key on the numeric keypad
197 * @SWFDEC_KEY_NUMPAD_2: the 2 key on the numeric keypad
198 * @SWFDEC_KEY_NUMPAD_3: the 3 key on the numeric keypad
199 * @SWFDEC_KEY_NUMPAD_4: the 4 key on the numeric keypad
200 * @SWFDEC_KEY_NUMPAD_5: the 5 key on the numeric keypad
201 * @SWFDEC_KEY_NUMPAD_6: the 6 key on the numeric keypad
202 * @SWFDEC_KEY_NUMPAD_7: the 7 key on the numeric keypad
203 * @SWFDEC_KEY_NUMPAD_8: the 8 key on the numeric keypad
204 * @SWFDEC_KEY_NUMPAD_9: the 9 key on the numeric keypad
205 * @SWFDEC_KEY_NUMPAD_MULTIPLY: the multiply key on the numeric keypad
206 * @SWFDEC_KEY_NUMPAD_ADD: the add key on the numeric keypad
207 * @SWFDEC_KEY_NUMPAD_SUBTRACT: the subtract key on the numeric keypad
208 * @SWFDEC_KEY_NUMPAD_DECIMAL: the decimal key on the numeric keypad
209 * @SWFDEC_KEY_NUMPAD_DIVIDE: the divide key on the numeric keypad
210 * @SWFDEC_KEY_F1: the F1 key
211 * @SWFDEC_KEY_F2: the F2 key
212 * @SWFDEC_KEY_F3: the F3 key
213 * @SWFDEC_KEY_F4: the F4 key
214 * @SWFDEC_KEY_F5: the F5 key
215 * @SWFDEC_KEY_F6: the F6 key
216 * @SWFDEC_KEY_F7: the F7 key
217 * @SWFDEC_KEY_F8: the F8 key
218 * @SWFDEC_KEY_F9: the F9 key
219 * @SWFDEC_KEY_F10: the F10 key
220 * @SWFDEC_KEY_F11: the F11 key
221 * @SWFDEC_KEY_F12: the F12 key
222 * @SWFDEC_KEY_F13: the F13 key
223 * @SWFDEC_KEY_F14: the F14 key
224 * @SWFDEC_KEY_F15: the F15 key
225 * @SWFDEC_KEY_NUM_LOCK: the num lock key
226 * @SWFDEC_KEY_SEMICOLON: the semicolon key (on English keyboards)
227 * @SWFDEC_KEY_EQUAL: the equal key (on English keyboards)
228 * @SWFDEC_KEY_MINUS: the minus key (on English keyboards)
229 * @SWFDEC_KEY_SLASH: the slash key (on English keyboards)
230 * @SWFDEC_KEY_GRAVE: the grave key (on English keyboards)
231 * @SWFDEC_KEY_LEFT_BRACKET: the left bracket key (on English keyboards)
232 * @SWFDEC_KEY_BACKSLASH: the backslash key (on English keyboards)
233 * @SWFDEC_KEY_RIGHT_BRACKET: the right bracket key (on English keyboards)
234 * @SWFDEC_KEY_APOSTROPHE: the apostrophe key (on English keyboards)
236 * Lists all known key codes in Swfdec and their meanings on an English
243 swfdec_player_get_next_event_time (SwfdecPlayer
*player
)
245 if (player
->timeouts
) {
246 return ((SwfdecTimeout
*) player
->timeouts
->data
)->timestamp
- player
->time
;
253 * swfdec_player_add_timeout:
254 * @player: a #SwfdecPlayer
255 * @timeout: timeout to add
257 * Adds a timeout to @player. The timeout will be removed automatically when
258 * triggered, so you need to use swfdec_player_add_timeout() to add it again.
259 * The #SwfdecTimeout struct and callback does not use a data callback pointer.
260 * It's suggested that you use the struct as part of your own bigger struct
261 * and get it back like this:
265 * SwfdecTimeout timeout;
269 * my_struct_timeout_callback (SwfdecTimeout *timeout)
271 * MyStruct *mystruct = (MyStruct *) ((void *) timeout - G_STRUCT_OFFSET (MyStruct, timeout));
278 swfdec_player_add_timeout (SwfdecPlayer
*player
, SwfdecTimeout
*timeout
)
281 SwfdecTick next_tick
;
283 g_return_if_fail (SWFDEC_IS_PLAYER (player
));
284 g_return_if_fail (timeout
!= NULL
);
285 g_return_if_fail (timeout
->timestamp
>= player
->time
);
286 g_return_if_fail (timeout
->callback
!= NULL
);
288 SWFDEC_LOG ("adding timeout %p in %"G_GUINT64_FORMAT
" msecs", timeout
,
289 SWFDEC_TICKS_TO_MSECS (timeout
->timestamp
- player
->time
));
290 next_tick
= swfdec_player_get_next_event_time (player
);
291 /* the order is important, on events with the same time, we make sure the new one is last */
292 for (walk
= player
->timeouts
; walk
; walk
= walk
->next
) {
293 SwfdecTimeout
*cur
= walk
->data
;
294 if (cur
->timestamp
> timeout
->timestamp
)
297 player
->timeouts
= g_list_insert_before (player
->timeouts
, walk
, timeout
);
298 if (next_tick
!= swfdec_player_get_next_event_time (player
))
299 g_object_notify (G_OBJECT (player
), "next-event");
303 * swfdec_player_remove_timeout:
304 * @player: a #SwfdecPlayer
305 * @timeout: a timeout that should be removed
307 * Removes the @timeout from the list of scheduled timeouts. The timeout must
308 * have been added with swfdec_player_add_timeout() before.
311 swfdec_player_remove_timeout (SwfdecPlayer
*player
, SwfdecTimeout
*timeout
)
313 SwfdecTick next_tick
;
315 g_return_if_fail (SWFDEC_IS_PLAYER (player
));
316 g_return_if_fail (timeout
!= NULL
);
317 g_return_if_fail (timeout
->timestamp
>= player
->time
);
318 g_return_if_fail (timeout
->callback
!= NULL
);
320 SWFDEC_LOG ("removing timeout %p", timeout
);
321 next_tick
= swfdec_player_get_next_event_time (player
);
322 player
->timeouts
= g_list_remove (player
->timeouts
, timeout
);
323 if (next_tick
!= swfdec_player_get_next_event_time (player
))
324 g_object_notify (G_OBJECT (player
), "next-event");
330 SwfdecMovie
* movie
; /* the movie to trigger the action on */
331 SwfdecScript
* script
; /* script to execute or NULL to trigger action */
332 SwfdecEventType event
; /* the action to trigger */
333 } SwfdecPlayerAction
;
337 SwfdecActionFunc func
;
339 } SwfdecPlayerExternalAction
;
342 swfdec_player_compress_actions (SwfdecRingBuffer
*buffer
)
344 SwfdecPlayerAction
*action
, tmp
;
347 for (i
= swfdec_ring_buffer_get_n_elements (buffer
); i
> 0; i
--) {
348 action
= swfdec_ring_buffer_pop (buffer
);
350 if (action
->movie
== NULL
)
353 action
= swfdec_ring_buffer_push (buffer
);
356 SWFDEC_INFO ("compresed action queue to %u elements",
357 swfdec_ring_buffer_get_n_elements (buffer
));
358 for (i
= 0; i
< swfdec_ring_buffer_get_n_elements (buffer
); i
++) {
359 action
= swfdec_ring_buffer_peek_nth (buffer
, i
);
360 g_assert (action
->movie
!= NULL
);
365 swfdec_player_do_add_action (SwfdecPlayer
*player
, guint importance
, SwfdecPlayerAction
*act
)
367 SwfdecPlayerAction
*action
= swfdec_ring_buffer_push (player
->actions
[importance
]);
368 if (action
== NULL
) {
369 /* try to get rid of freed actions */
370 swfdec_player_compress_actions (player
->actions
[importance
]);
371 action
= swfdec_ring_buffer_push (player
->actions
[importance
]);
372 if (action
== NULL
) {
373 if (swfdec_ring_buffer_get_size (player
->actions
[importance
]) == 256) {
374 SWFDEC_WARNING ("256 levels of recursion were exceeded in one action list.");
376 swfdec_ring_buffer_set_size (player
->actions
[importance
],
377 swfdec_ring_buffer_get_size (player
->actions
[importance
]) + 16);
378 action
= swfdec_ring_buffer_push (player
->actions
[importance
]);
386 * swfdec_player_add_event:
387 * @player: a #SwfdecPlayer
388 * @movie: the movie on which to trigger the event
389 * @type: type of the event
390 * @importance: importance of the event
392 * Adds an action to the @player. Actions are used by Flash player to solve
393 * reentrancy issues. Instead of calling back into the Actionscript engine,
394 * an action is queued for later execution. So if you're writing code that
395 * is calling Actionscript code, you want to do this by using actions.
398 swfdec_player_add_action (SwfdecPlayer
*player
, SwfdecMovie
*movie
, SwfdecEventType type
,
401 SwfdecPlayerAction action
= { movie
, NULL
, type
};
403 g_return_if_fail (SWFDEC_IS_PLAYER (player
));
404 g_return_if_fail (SWFDEC_IS_MOVIE (movie
));
405 g_return_if_fail (importance
< SWFDEC_PLAYER_N_ACTION_QUEUES
);
407 SWFDEC_LOG ("adding action %s %u", movie
->name
, type
);
408 swfdec_player_do_add_action (player
, importance
, &action
);
412 swfdec_player_add_action_script (SwfdecPlayer
*player
, SwfdecMovie
*movie
,
413 SwfdecScript
*script
, guint importance
)
415 SwfdecPlayerAction action
= { movie
, script
, 0 };
417 g_return_if_fail (SWFDEC_IS_PLAYER (player
));
418 g_return_if_fail (SWFDEC_IS_MOVIE (movie
));
419 g_return_if_fail (script
!= NULL
);
420 g_return_if_fail (importance
< SWFDEC_PLAYER_N_ACTION_QUEUES
);
422 SWFDEC_LOG ("adding action script %s %s", movie
->name
, script
->name
);
423 swfdec_player_do_add_action (player
, importance
, &action
);
427 * swfdec_player_remove_all_actions:
428 * @player: a #SwfdecPlayer
429 * @movie: movie pointer identifying the actions to be removed
431 * Removes all actions associated with @movie that have not yet been executed.
432 * See swfdec_player_add_action() for details about actions.
435 swfdec_player_remove_all_actions (SwfdecPlayer
*player
, SwfdecMovie
*movie
)
437 SwfdecPlayerAction
*action
;
440 g_return_if_fail (SWFDEC_IS_PLAYER (player
));
441 g_return_if_fail (SWFDEC_IS_MOVIE (movie
));
443 for (i
= 0; i
< SWFDEC_PLAYER_N_ACTION_QUEUES
; i
++) {
444 for (j
= 0; j
< swfdec_ring_buffer_get_n_elements (player
->actions
[i
]); j
++) {
445 action
= swfdec_ring_buffer_peek_nth (player
->actions
[i
], j
);
447 if (action
->movie
== movie
) {
448 SWFDEC_LOG ("removing action %p %u",
449 action
->movie
, action
->event
);
450 action
->movie
= NULL
;
457 swfdec_player_do_action (SwfdecPlayer
*player
)
459 SwfdecPlayerAction
*action
;
462 for (i
= 0; i
< SWFDEC_PLAYER_N_ACTION_QUEUES
; i
++) {
464 action
= swfdec_ring_buffer_pop (player
->actions
[i
]);
467 } while (action
->movie
== NULL
); /* skip removed actions */
469 if (action
->script
) {
470 swfdec_as_object_run_with_security (SWFDEC_AS_OBJECT (action
->movie
),
471 action
->script
, SWFDEC_SECURITY (action
->movie
->resource
));
473 swfdec_movie_execute (action
->movie
, action
->event
);
483 swfdec_player_perform_external_actions (SwfdecPlayer
*player
)
485 SwfdecPlayerExternalAction
*action
;
488 /* remove timeout if it exists - do this before executing stuff below */
489 if (player
->external_timeout
.callback
) {
490 swfdec_player_remove_timeout (player
, &player
->external_timeout
);
491 player
->external_timeout
.callback
= NULL
;
494 /* we need to query the number of current actions so newly added ones aren't
495 * executed in here */
496 for (i
= swfdec_ring_buffer_get_n_elements (player
->external_actions
); i
> 0; i
--) {
497 action
= swfdec_ring_buffer_pop (player
->external_actions
);
498 g_assert (action
!= NULL
);
499 /* skip removed actions */
500 if (action
->object
== NULL
)
502 action
->func (action
->object
, action
->data
);
503 swfdec_player_perform_actions (player
);
508 swfdec_player_trigger_external_actions (SwfdecTimeout
*advance
)
510 SwfdecPlayer
*player
= SWFDEC_PLAYER ((guint8
*) advance
- G_STRUCT_OFFSET (SwfdecPlayer
, external_timeout
));
512 player
->external_timeout
.callback
= NULL
;
513 swfdec_player_perform_external_actions (player
);
517 swfdec_player_add_external_action (SwfdecPlayer
*player
, gpointer object
,
518 SwfdecActionFunc action_func
, gpointer action_data
)
520 SwfdecPlayerExternalAction
*action
;
522 g_return_if_fail (SWFDEC_IS_PLAYER (player
));
523 g_return_if_fail (object
!= NULL
);
524 g_return_if_fail (action_func
!= NULL
);
526 SWFDEC_LOG ("adding external action %p %p %p", object
, action_func
, action_data
);
527 action
= swfdec_ring_buffer_push (player
->external_actions
);
528 if (action
== NULL
) {
529 /* FIXME: limit number of actions to not get inf loops due to scripts? */
530 swfdec_ring_buffer_set_size (player
->external_actions
,
531 swfdec_ring_buffer_get_size (player
->external_actions
) + 16);
532 action
= swfdec_ring_buffer_push (player
->external_actions
);
535 action
->object
= object
;
536 action
->func
= action_func
;
537 action
->data
= action_data
;
538 if (!player
->external_timeout
.callback
) {
539 /* trigger execution immediately.
540 * But if initialized, keep at least 100ms from when the last external
541 * timeout triggered. This is a crude method to get around infinite loops
542 * when script actions executed by external actions trigger another external
543 * action that would execute instantly.
545 if (player
->initialized
) {
546 player
->external_timeout
.timestamp
= MAX (player
->time
,
547 player
->external_timeout
.timestamp
+ SWFDEC_MSECS_TO_TICKS (100));
549 player
->external_timeout
.timestamp
= player
->time
;
551 player
->external_timeout
.callback
= swfdec_player_trigger_external_actions
;
552 swfdec_player_add_timeout (player
, &player
->external_timeout
);
557 swfdec_player_remove_all_external_actions (SwfdecPlayer
*player
, gpointer object
)
559 SwfdecPlayerExternalAction
*action
;
562 g_return_if_fail (SWFDEC_IS_PLAYER (player
));
563 g_return_if_fail (object
!= NULL
);
565 for (i
= 0; i
< swfdec_ring_buffer_get_n_elements (player
->external_actions
); i
++) {
566 action
= swfdec_ring_buffer_peek_nth (player
->external_actions
, i
);
568 if (action
->object
== object
) {
569 SWFDEC_LOG ("removing external action %p %p %p",
570 action
->object
, action
->func
, action
->data
);
571 action
->object
= NULL
;
576 /*** SwfdecPlayer ***/
590 static guint signals
[LAST_SIGNAL
] = { 0, };
601 PROP_BACKGROUND_COLOR
,
610 G_DEFINE_TYPE (SwfdecPlayer
, swfdec_player
, SWFDEC_TYPE_AS_CONTEXT
)
613 swfdec_player_remove_movie (SwfdecPlayer
*player
, SwfdecMovie
*movie
)
615 swfdec_movie_remove (movie
);
616 player
->movies
= g_list_remove (player
->movies
, movie
);
620 swfdec_player_alignment_to_flags (SwfdecAlignment alignment
)
622 static const guint align_flags
[9] = {
623 SWFDEC_ALIGN_FLAG_TOP
| SWFDEC_ALIGN_FLAG_LEFT
,
624 SWFDEC_ALIGN_FLAG_TOP
,
625 SWFDEC_ALIGN_FLAG_TOP
| SWFDEC_ALIGN_FLAG_RIGHT
,
626 SWFDEC_ALIGN_FLAG_LEFT
,
628 SWFDEC_ALIGN_FLAG_RIGHT
,
629 SWFDEC_ALIGN_FLAG_BOTTOM
| SWFDEC_ALIGN_FLAG_LEFT
,
630 SWFDEC_ALIGN_FLAG_BOTTOM
,
631 SWFDEC_ALIGN_FLAG_BOTTOM
| SWFDEC_ALIGN_FLAG_RIGHT
633 return align_flags
[alignment
];
636 static SwfdecAlignment
637 swfdec_player_alignment_from_flags (guint flags
)
639 if (flags
& SWFDEC_ALIGN_FLAG_TOP
) {
640 if (flags
& SWFDEC_ALIGN_FLAG_LEFT
) {
641 return SWFDEC_ALIGNMENT_TOP_LEFT
;
642 } else if (flags
& SWFDEC_ALIGN_FLAG_RIGHT
) {
643 return SWFDEC_ALIGNMENT_TOP_RIGHT
;
645 return SWFDEC_ALIGNMENT_TOP
;
647 } else if (flags
& SWFDEC_ALIGN_FLAG_BOTTOM
) {
648 if (flags
& SWFDEC_ALIGN_FLAG_LEFT
) {
649 return SWFDEC_ALIGNMENT_BOTTOM_LEFT
;
650 } else if (flags
& SWFDEC_ALIGN_FLAG_RIGHT
) {
651 return SWFDEC_ALIGNMENT_BOTTOM_RIGHT
;
653 return SWFDEC_ALIGNMENT_BOTTOM
;
656 if (flags
& SWFDEC_ALIGN_FLAG_LEFT
) {
657 return SWFDEC_ALIGNMENT_LEFT
;
658 } else if (flags
& SWFDEC_ALIGN_FLAG_RIGHT
) {
659 return SWFDEC_ALIGNMENT_RIGHT
;
661 return SWFDEC_ALIGNMENT_CENTER
;
667 swfdec_player_get_property (GObject
*object
, guint param_id
, GValue
*value
,
670 SwfdecPlayer
*player
= SWFDEC_PLAYER (object
);
673 case PROP_BACKGROUND_COLOR
:
674 g_value_set_uint (value
, swfdec_player_get_background_color (player
));
676 case PROP_CACHE_SIZE
:
677 g_value_set_uint (value
, player
->cache
->max_size
);
679 case PROP_INITIALIZED
:
680 g_value_set_boolean (value
, swfdec_player_is_initialized (player
));
682 case PROP_DEFAULT_WIDTH
:
683 g_value_set_uint (value
, player
->width
);
685 case PROP_DEFAULT_HEIGHT
:
686 g_value_set_uint (value
, player
->height
);
689 g_value_set_double (value
, player
->rate
/ 256.0);
691 case PROP_MOUSE_CURSOR
:
692 g_value_set_enum (value
, player
->mouse_cursor
);
694 case PROP_NEXT_EVENT
:
695 g_value_set_uint (value
, swfdec_player_get_next_event (player
));
698 g_value_set_int (value
, player
->stage_width
);
701 g_value_set_int (value
, player
->stage_height
);
704 g_value_set_enum (value
, swfdec_player_alignment_from_flags (player
->align_flags
));
707 g_value_set_enum (value
, player
->scale_mode
);
710 g_value_set_object (value
, player
->system
);
712 case PROP_MAX_RUNTIME
:
713 g_value_set_ulong (value
, player
->max_runtime
);
716 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, param_id
, pspec
);
722 swfdec_player_update_scale (SwfdecPlayer
*player
)
725 double scale_x
, scale_y
;
727 player
->stage
.width
= player
->stage_width
>= 0 ? player
->stage_width
: (int) player
->width
;
728 player
->stage
.height
= player
->stage_height
>= 0 ? player
->stage_height
: (int) player
->height
;
729 if (player
->stage
.height
== 0 || player
->stage
.width
== 0) {
730 player
->scale_x
= 1.0;
731 player
->scale_y
= 1.0;
732 player
->offset_x
= 0;
733 player
->offset_y
= 0;
736 if (player
->width
== 0 || player
->height
== 0) {
740 scale_x
= (double) player
->stage
.width
/ player
->width
;
741 scale_y
= (double) player
->stage
.height
/ player
->height
;
743 switch (player
->scale_mode
) {
744 case SWFDEC_SCALE_SHOW_ALL
:
745 player
->scale_x
= MIN (scale_x
, scale_y
);
746 player
->scale_y
= player
->scale_x
;
748 case SWFDEC_SCALE_NO_BORDER
:
749 player
->scale_x
= MAX (scale_x
, scale_y
);
750 player
->scale_y
= player
->scale_x
;
752 case SWFDEC_SCALE_EXACT_FIT
:
753 player
->scale_x
= scale_x
;
754 player
->scale_y
= scale_y
;
756 case SWFDEC_SCALE_NONE
:
757 player
->scale_x
= 1.0;
758 player
->scale_y
= 1.0;
761 g_assert_not_reached ();
763 width
= player
->stage
.width
- ceil (player
->width
* player
->scale_x
);
764 height
= player
->stage
.height
- ceil (player
->height
* player
->scale_y
);
765 if (player
->align_flags
& SWFDEC_ALIGN_FLAG_LEFT
) {
766 player
->offset_x
= 0;
767 } else if (player
->align_flags
& SWFDEC_ALIGN_FLAG_RIGHT
) {
768 player
->offset_x
= width
;
770 player
->offset_x
= width
/ 2;
772 if (player
->align_flags
& SWFDEC_ALIGN_FLAG_TOP
) {
773 player
->offset_y
= 0;
774 } else if (player
->align_flags
& SWFDEC_ALIGN_FLAG_BOTTOM
) {
775 player
->offset_y
= height
;
777 player
->offset_y
= height
/ 2;
779 SWFDEC_LOG ("coordinate translation is %g * x + %d - %g * y + %d",
780 player
->scale_x
, player
->offset_x
, player
->scale_y
, player
->offset_y
);
782 /* FIXME: make this emit the signal at the right time */
783 player
->invalid
.x0
= 0;
784 player
->invalid
.y0
= 0;
785 player
->invalid
.x1
= player
->stage_width
;
786 player
->invalid
.y1
= player
->stage_height
;
791 swfdec_player_set_property (GObject
*object
, guint param_id
, const GValue
*value
,
794 SwfdecPlayer
*player
= SWFDEC_PLAYER (object
);
797 case PROP_BACKGROUND_COLOR
:
798 swfdec_player_set_background_color (player
, g_value_get_uint (value
));
800 case PROP_CACHE_SIZE
:
801 player
->cache
->max_size
= g_value_get_uint (value
);
804 swfdec_player_set_size (player
, g_value_get_int (value
), player
->stage_height
);
807 swfdec_player_set_size (player
, player
->stage_width
, g_value_get_int (value
));
810 player
->align_flags
= swfdec_player_alignment_to_flags (g_value_get_enum (value
));
811 swfdec_player_update_scale (player
);
814 swfdec_player_set_scale_mode (player
, g_value_get_enum (value
));
817 g_object_unref (player
->system
);
818 if (g_value_get_object (value
)) {
819 player
->system
= SWFDEC_SYSTEM (g_value_dup_object (value
));
821 player
->system
= swfdec_system_new ();
824 case PROP_MAX_RUNTIME
:
825 swfdec_player_set_maximum_runtime (player
, g_value_get_ulong (value
));
828 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, param_id
, pspec
);
834 swfdec_player_dispose (GObject
*object
)
836 SwfdecPlayer
*player
= SWFDEC_PLAYER (object
);
839 swfdec_player_stop_all_sounds (player
);
840 swfdec_player_resource_request_finish (player
);
841 g_hash_table_destroy (player
->registered_classes
);
843 while (player
->roots
)
844 swfdec_movie_destroy (player
->roots
->data
);
845 if (player
->resource
) {
846 g_object_unref (player
->resource
);
847 player
->resource
= NULL
;
849 while (player
->rooted_objects
)
850 swfdec_player_unroot_object (player
, player
->rooted_objects
->data
);
852 /* we do this here so references to GC'd objects get freed */
853 G_OBJECT_CLASS (swfdec_player_parent_class
)->dispose (object
);
855 swfdec_player_remove_all_external_actions (player
, player
);
856 #ifndef G_DISABLE_ASSERT
858 SwfdecPlayerExternalAction
*action
;
859 while ((action
= swfdec_ring_buffer_pop (player
->external_actions
)) != NULL
) {
860 g_assert (action
->object
== NULL
); /* skip removed actions */
864 SwfdecPlayerAction
*action
;
865 for (i
= 0; i
< SWFDEC_PLAYER_N_ACTION_QUEUES
; i
++) {
866 while ((action
= swfdec_ring_buffer_pop (player
->actions
[i
])) != NULL
) {
867 g_assert (action
->movie
== NULL
); /* skip removed actions */
872 swfdec_ring_buffer_free (player
->external_actions
);
873 for (i
= 0; i
< SWFDEC_PLAYER_N_ACTION_QUEUES
; i
++) {
874 swfdec_ring_buffer_free (player
->actions
[i
]);
876 g_assert (player
->movies
== NULL
);
877 g_assert (player
->audio
== NULL
);
878 if (player
->external_timeout
.callback
)
879 swfdec_player_remove_timeout (player
, &player
->external_timeout
);
881 swfdec_player_remove_timeout (player
, &player
->iterate_timeout
);
883 g_assert (player
->timeouts
== NULL
);
884 g_list_free (player
->intervals
);
885 player
->intervals
= NULL
;
886 swfdec_cache_unref (player
->cache
);
887 if (player
->system
) {
888 g_object_unref (player
->system
);
889 player
->system
= NULL
;
891 g_array_free (player
->invalidations
, TRUE
);
892 player
->invalidations
= NULL
;
893 if (player
->runtime
) {
894 g_timer_destroy (player
->runtime
);
895 player
->runtime
= NULL
;
900 swfdec_player_broadcast (SwfdecPlayer
*player
, const char *object_name
, const char *signal
)
905 SWFDEC_DEBUG ("broadcasting message %s.%s", object_name
, signal
);
906 obj
= SWFDEC_AS_CONTEXT (player
)->global
;
907 swfdec_as_object_get_variable (obj
, object_name
, &val
);
908 if (!SWFDEC_AS_VALUE_IS_OBJECT (&val
))
910 obj
= SWFDEC_AS_VALUE_GET_OBJECT (&val
);
911 SWFDEC_AS_VALUE_SET_STRING (&val
, signal
);
912 swfdec_as_object_call (obj
, SWFDEC_AS_STR_broadcastMessage
, 1, &val
, NULL
);
916 swfdec_player_update_mouse_cursor (SwfdecPlayer
*player
)
918 SwfdecMouseCursor
new = SWFDEC_MOUSE_CURSOR_NORMAL
;
920 if (!player
->mouse_visible
) {
921 new = SWFDEC_MOUSE_CURSOR_NONE
;
922 } else if (player
->mouse_grab
!= NULL
) {
923 /* FIXME: this needs to be more sophisticated, since SwfdecEditText may
924 * want to have different mouse cursors depending on location (it supports
927 if (SWFDEC_IS_BUTTON_MOVIE (player
->mouse_grab
))
928 new = SWFDEC_MOUSE_CURSOR_CLICK
;
931 if (new != player
->mouse_cursor
) {
932 player
->mouse_cursor
= new;
933 g_object_notify (G_OBJECT (player
), "mouse-cursor");
938 swfdec_player_update_drag_movie (SwfdecPlayer
*player
)
943 if (player
->mouse_drag
== NULL
)
946 movie
= player
->mouse_drag
;
947 g_assert (movie
->cache_state
== SWFDEC_MOVIE_UP_TO_DATE
);
950 swfdec_player_stage_to_global (player
, &x
, &y
);
952 swfdec_movie_global_to_local (movie
->parent
, &x
, &y
);
953 if (player
->mouse_drag_center
) {
954 x
-= (movie
->extents
.x1
- movie
->extents
.x0
) / 2;
955 y
-= (movie
->extents
.y1
- movie
->extents
.y0
) / 2;
957 x
-= player
->mouse_drag_x
;
958 y
-= player
->mouse_drag_y
;
960 x
= CLAMP (x
, player
->mouse_drag_rect
.x0
, player
->mouse_drag_rect
.x1
);
961 y
= CLAMP (y
, player
->mouse_drag_rect
.y0
, player
->mouse_drag_rect
.y1
);
962 SWFDEC_LOG ("mouse is at %g %g, originally (%g %g)", x
, y
, player
->mouse_x
, player
->mouse_y
);
963 if (x
!= movie
->matrix
.x0
|| y
!= movie
->matrix
.y0
) {
964 movie
->matrix
.x0
= x
;
965 movie
->matrix
.y0
= y
;
966 swfdec_movie_queue_update (movie
, SWFDEC_MOVIE_INVALID_MATRIX
);
971 * swfdec_player_set_drag_movie:
972 * @player: a #SwfdecPlayer
973 * @drag: the movie to be dragged by the mouse or NULL to unset
974 * @center: TRUE if the center of @drag should be at the mouse pointer, FALSE if (0,0)
975 * of @drag should be at the mouse pointer.
976 * @rect: NULL or the rectangle that clips the mouse position. The coordinates
977 * are in the coordinate system of the parent of @drag.
979 * Sets or unsets the movie that is dragged by the mouse.
982 swfdec_player_set_drag_movie (SwfdecPlayer
*player
, SwfdecMovie
*drag
, gboolean center
,
985 g_return_if_fail (SWFDEC_IS_PLAYER (player
));
986 g_return_if_fail (drag
== NULL
|| SWFDEC_IS_MOVIE (drag
));
988 /* FIXME: need to do anything with old drag? */
989 player
->mouse_drag
= drag
;
990 player
->mouse_drag_center
= center
;
991 if (drag
&& !center
) {
992 player
->mouse_drag_x
= player
->mouse_x
;
993 player
->mouse_drag_y
= player
->mouse_y
;
994 swfdec_player_stage_to_global (player
, &player
->mouse_drag_x
, &player
->mouse_drag_y
);
996 swfdec_movie_global_to_local (drag
->parent
, &player
->mouse_drag_x
, &player
->mouse_drag_y
);
997 player
->mouse_drag_x
-= drag
->matrix
.x0
;
998 player
->mouse_drag_y
-= drag
->matrix
.y0
;
1001 player
->mouse_drag_rect
= *rect
;
1003 player
->mouse_drag_rect
.x0
= -G_MAXDOUBLE
;
1004 player
->mouse_drag_rect
.y0
= -G_MAXDOUBLE
;
1005 player
->mouse_drag_rect
.x1
= G_MAXDOUBLE
;
1006 player
->mouse_drag_rect
.y1
= G_MAXDOUBLE
;
1008 SWFDEC_DEBUG ("starting drag in %g %g %g %g",
1009 player
->mouse_drag_rect
.x0
, player
->mouse_drag_rect
.y0
,
1010 player
->mouse_drag_rect
.x1
, player
->mouse_drag_rect
.y1
);
1011 /* FIXME: need a way to make sure we get updated */
1013 swfdec_movie_update (drag
);
1014 drag
->modified
= TRUE
;
1015 swfdec_player_update_drag_movie (player
);
1020 swfdec_player_update_mouse_position (SwfdecPlayer
*player
)
1023 SwfdecMovie
*mouse_grab
= NULL
;
1025 if (player
->mouse_button
) {
1026 mouse_grab
= player
->mouse_grab
;
1029 /* if the mouse button is pressed the grab widget stays the same (I think) */
1030 x
= player
->mouse_x
;
1031 y
= player
->mouse_y
;
1032 swfdec_player_stage_to_global (player
, &x
, &y
);
1033 for (walk
= g_list_last (player
->roots
); walk
; walk
= walk
->prev
) {
1034 mouse_grab
= swfdec_movie_get_movie_at (walk
->data
, x
, y
);
1039 SWFDEC_DEBUG ("%s %p has mouse at %g %g",
1040 mouse_grab
? G_OBJECT_TYPE_NAME (mouse_grab
) : "---",
1041 mouse_grab
, player
->mouse_x
, player
->mouse_y
);
1042 if (player
->mouse_grab
&& mouse_grab
!= player
->mouse_grab
)
1043 swfdec_movie_send_mouse_change (player
->mouse_grab
, TRUE
);
1044 player
->mouse_grab
= mouse_grab
;
1046 swfdec_movie_send_mouse_change (mouse_grab
, FALSE
);
1050 swfdec_player_do_mouse_move (SwfdecPlayer
*player
)
1054 swfdec_player_update_drag_movie (player
);
1055 for (walk
= player
->movies
; walk
; walk
= walk
->next
) {
1056 swfdec_movie_queue_script (walk
->data
, SWFDEC_EVENT_MOUSE_MOVE
);
1058 swfdec_player_broadcast (player
, SWFDEC_AS_STR_Mouse
, SWFDEC_AS_STR_onMouseMove
);
1059 swfdec_player_update_mouse_position (player
);
1063 swfdec_player_do_mouse_button (SwfdecPlayer
*player
)
1067 const char *event_name
;
1069 if (player
->mouse_button
) {
1070 event
= SWFDEC_EVENT_MOUSE_DOWN
;
1071 event_name
= SWFDEC_AS_STR_onMouseDown
;
1073 event
= SWFDEC_EVENT_MOUSE_UP
;
1074 event_name
= SWFDEC_AS_STR_onMouseUp
;
1076 for (walk
= player
->movies
; walk
; walk
= walk
->next
) {
1077 swfdec_movie_queue_script (walk
->data
, event
);
1079 swfdec_player_broadcast (player
, SWFDEC_AS_STR_Mouse
, event_name
);
1080 if (player
->mouse_grab
)
1081 swfdec_movie_send_mouse_change (player
->mouse_grab
, FALSE
);
1085 swfdec_player_emit_signals (SwfdecPlayer
*player
)
1089 /* emit invalidate signal */
1090 if (!swfdec_rectangle_is_empty (&player
->invalid_extents
)) {
1091 g_signal_emit (player
, signals
[INVALIDATE
], 0, &player
->invalid_extents
,
1092 player
->invalidations
->data
, player
->invalidations
->len
);
1093 swfdec_rectangle_init_empty (&player
->invalid_extents
);
1094 g_array_set_size (player
->invalidations
, 0);
1097 /* emit audio-added for all added audio streams */
1098 for (walk
= player
->audio
; walk
; walk
= walk
->next
) {
1099 SwfdecAudio
*audio
= walk
->data
;
1103 g_signal_emit (player
, signals
[AUDIO_ADDED
], 0, audio
);
1104 audio
->added
= TRUE
;
1109 swfdec_player_do_handle_key (SwfdecPlayer
*player
, guint keycode
, guint character
, gboolean down
)
1111 g_assert (keycode
< 256);
1113 if (!swfdec_player_lock (player
))
1115 /* set the correct variables */
1116 player
->last_keycode
= keycode
;
1117 player
->last_character
= character
;
1119 player
->key_pressed
[keycode
/ 8] |= 1 << keycode
% 8;
1121 player
->key_pressed
[keycode
/ 8] &= ~(1 << keycode
% 8);
1123 swfdec_player_broadcast (player
, SWFDEC_AS_STR_Key
, down
? SWFDEC_AS_STR_onKeyDown
: SWFDEC_AS_STR_onKeyUp
);
1124 swfdec_player_perform_actions (player
);
1125 swfdec_player_unlock (player
);
1131 swfdec_player_do_handle_mouse (SwfdecPlayer
*player
,
1132 double x
, double y
, int button
)
1134 if (!swfdec_player_lock (player
))
1137 SWFDEC_LOG ("handling mouse at %g %g %d", x
, y
, button
);
1138 if (player
->mouse_x
!= x
|| player
->mouse_y
!= y
) {
1139 player
->mouse_x
= x
;
1140 player
->mouse_y
= y
;
1141 swfdec_player_do_mouse_move (player
);
1143 if (player
->mouse_button
!= button
) {
1144 player
->mouse_button
= button
;
1145 swfdec_player_do_mouse_button (player
);
1147 swfdec_player_perform_actions (player
);
1148 swfdec_player_unlock (player
);
1150 /* FIXME: allow events to pass through */
1155 swfdec_player_global_to_stage (SwfdecPlayer
*player
, double *x
, double *y
)
1157 g_return_if_fail (SWFDEC_IS_PLAYER (player
));
1158 g_return_if_fail (x
!= NULL
);
1159 g_return_if_fail (y
!= NULL
);
1161 *x
= *x
/ SWFDEC_TWIPS_SCALE_FACTOR
* player
->scale_x
+ player
->offset_x
;
1162 *y
= *y
/ SWFDEC_TWIPS_SCALE_FACTOR
* player
->scale_y
+ player
->offset_y
;
1166 swfdec_player_stage_to_global (SwfdecPlayer
*player
, double *x
, double *y
)
1168 g_return_if_fail (SWFDEC_IS_PLAYER (player
));
1169 g_return_if_fail (x
!= NULL
);
1170 g_return_if_fail (y
!= NULL
);
1172 *x
= (*x
- player
->offset_x
) / player
->scale_x
* SWFDEC_TWIPS_SCALE_FACTOR
;
1173 *y
= (*y
- player
->offset_y
) / player
->scale_y
* SWFDEC_TWIPS_SCALE_FACTOR
;
1177 swfdec_player_execute_on_load_init (SwfdecPlayer
*player
)
1181 /* FIXME: This can be made a LOT faster with correct caching, but I'm lazy */
1183 for (walk
= player
->movies
; walk
; walk
= walk
->next
) {
1184 SwfdecMovie
*movie
= walk
->data
;
1185 SwfdecResource
*resource
= swfdec_movie_get_own_resource (movie
);
1186 if (resource
== NULL
)
1188 if (swfdec_resource_emit_on_load_init (resource
))
1191 } while (walk
!= NULL
);
1195 swfdec_player_iterate (SwfdecTimeout
*timeout
)
1197 SwfdecPlayer
*player
= SWFDEC_PLAYER ((guint8
*) timeout
- G_STRUCT_OFFSET (SwfdecPlayer
, iterate_timeout
));
1200 /* add timeout again - do this first because later code can change it */
1201 /* FIXME: rounding issues? */
1202 player
->iterate_timeout
.timestamp
+= SWFDEC_TICKS_PER_SECOND
* 256 / player
->rate
;
1203 swfdec_player_add_timeout (player
, &player
->iterate_timeout
);
1204 swfdec_player_perform_external_actions (player
);
1205 SWFDEC_INFO ("=== START ITERATION ===");
1206 /* start the iteration. This performs a goto next frame on all
1207 * movies that are not stopped. It also queues onEnterFrame.
1209 for (walk
= player
->movies
; walk
; walk
= walk
->next
) {
1210 SwfdecMovieClass
*klass
= SWFDEC_MOVIE_GET_CLASS (walk
->data
);
1211 if (klass
->iterate_start
)
1212 klass
->iterate_start (walk
->data
);
1214 swfdec_player_perform_actions (player
);
1215 SWFDEC_INFO ("=== STOP ITERATION ===");
1216 /* this loop allows removal of walk->data */
1217 walk
= player
->movies
;
1219 SwfdecMovie
*cur
= walk
->data
;
1220 SwfdecMovieClass
*klass
= SWFDEC_MOVIE_GET_CLASS (cur
);
1222 g_assert (klass
->iterate_end
);
1223 if (!klass
->iterate_end (cur
))
1224 swfdec_movie_destroy (cur
);
1226 swfdec_player_execute_on_load_init (player
);
1227 swfdec_player_resource_request_perform (player
);
1228 swfdec_player_perform_actions (player
);
1232 swfdec_player_advance_audio (SwfdecPlayer
*player
, guint samples
)
1240 /* don't use for loop here, because we need to advance walk before
1241 * removing the audio */
1242 walk
= player
->audio
;
1246 if (swfdec_audio_iterate (audio
, samples
) == 0)
1247 swfdec_audio_remove (audio
);
1252 swfdec_player_do_advance (SwfdecPlayer
*player
, gulong msecs
, guint audio_samples
)
1254 SwfdecTimeout
*timeout
;
1255 SwfdecTick target_time
;
1258 if (!swfdec_player_lock (player
))
1261 target_time
= player
->time
+ SWFDEC_MSECS_TO_TICKS (msecs
);
1262 SWFDEC_DEBUG ("advancing %lu msecs (%u audio frames)", msecs
, audio_samples
);
1264 for (timeout
= player
->timeouts
? player
->timeouts
->data
: NULL
;
1265 timeout
&& timeout
->timestamp
<= target_time
;
1266 timeout
= player
->timeouts
? player
->timeouts
->data
: NULL
) {
1267 player
->timeouts
= g_list_remove (player
->timeouts
, timeout
);
1268 frames_now
= SWFDEC_TICKS_TO_SAMPLES (timeout
->timestamp
) -
1269 SWFDEC_TICKS_TO_SAMPLES (player
->time
);
1270 player
->time
= timeout
->timestamp
;
1271 swfdec_player_advance_audio (player
, frames_now
);
1272 audio_samples
-= frames_now
;
1273 SWFDEC_LOG ("activating timeout %p now (timeout is %"G_GUINT64_FORMAT
", target time is %"G_GUINT64_FORMAT
,
1274 timeout
, timeout
->timestamp
, target_time
);
1275 timeout
->callback (timeout
);
1276 swfdec_player_perform_actions (player
);
1278 if (target_time
> player
->time
) {
1279 frames_now
= SWFDEC_TICKS_TO_SAMPLES (target_time
) -
1280 SWFDEC_TICKS_TO_SAMPLES (player
->time
);
1281 player
->time
= target_time
;
1282 swfdec_player_advance_audio (player
, frames_now
);
1283 audio_samples
-= frames_now
;
1285 g_assert (audio_samples
== 0);
1287 swfdec_player_unlock (player
);
1291 swfdec_player_perform_actions (SwfdecPlayer
*player
)
1295 g_return_if_fail (SWFDEC_IS_PLAYER (player
));
1297 while (swfdec_player_do_action (player
));
1298 for (walk
= player
->roots
; walk
; walk
= walk
->next
) {
1299 swfdec_movie_update (walk
->data
);
1301 /* update the state of the mouse when stuff below it moved */
1302 if (swfdec_rectangle_contains_point (&player
->invalid_extents
, player
->mouse_x
, player
->mouse_y
)) {
1303 SWFDEC_INFO ("=== NEED TO UPDATE mouse post-iteration ===");
1304 swfdec_player_update_mouse_position (player
);
1305 while (swfdec_player_do_action (player
));
1306 for (walk
= player
->roots
; walk
; walk
= walk
->next
) {
1307 swfdec_movie_update (walk
->data
);
1312 /* used for breakpoints */
1314 swfdec_player_lock_soft (SwfdecPlayer
*player
)
1316 g_return_if_fail (SWFDEC_IS_PLAYER (player
));
1317 g_assert (swfdec_rectangle_is_empty (&player
->invalid_extents
));
1319 g_object_freeze_notify (G_OBJECT (player
));
1320 g_timer_start (player
->runtime
);
1321 SWFDEC_DEBUG ("LOCKED");
1325 swfdec_player_lock (SwfdecPlayer
*player
)
1327 g_return_val_if_fail (SWFDEC_IS_PLAYER (player
), FALSE
);
1328 g_assert (swfdec_ring_buffer_get_n_elements (player
->actions
[0]) == 0);
1329 g_assert (swfdec_ring_buffer_get_n_elements (player
->actions
[1]) == 0);
1330 g_assert (swfdec_ring_buffer_get_n_elements (player
->actions
[2]) == 0);
1331 g_assert (swfdec_ring_buffer_get_n_elements (player
->actions
[3]) == 0);
1333 if (swfdec_as_context_is_aborted (SWFDEC_AS_CONTEXT (player
)))
1336 g_object_ref (player
);
1337 swfdec_player_lock_soft (player
);
1341 /* used for breakpoints */
1343 swfdec_player_unlock_soft (SwfdecPlayer
*player
)
1345 g_return_if_fail (SWFDEC_IS_PLAYER (player
));
1347 SWFDEC_DEBUG ("UNLOCK");
1348 g_timer_stop (player
->runtime
);
1349 swfdec_player_update_mouse_cursor (player
);
1350 g_object_thaw_notify (G_OBJECT (player
));
1351 swfdec_player_emit_signals (player
);
1355 swfdec_player_unlock (SwfdecPlayer
*player
)
1357 SwfdecAsContext
*context
;
1359 g_return_if_fail (SWFDEC_IS_PLAYER (player
));
1360 g_assert (swfdec_ring_buffer_get_n_elements (player
->actions
[0]) == 0);
1361 g_assert (swfdec_ring_buffer_get_n_elements (player
->actions
[1]) == 0);
1362 g_assert (swfdec_ring_buffer_get_n_elements (player
->actions
[2]) == 0);
1363 g_assert (swfdec_ring_buffer_get_n_elements (player
->actions
[3]) == 0);
1364 context
= SWFDEC_AS_CONTEXT (player
);
1365 g_return_if_fail (context
->state
!= SWFDEC_AS_CONTEXT_INTERRUPTED
);
1367 if (context
->state
== SWFDEC_AS_CONTEXT_RUNNING
)
1368 swfdec_as_context_maybe_gc (SWFDEC_AS_CONTEXT (player
));
1369 swfdec_player_unlock_soft (player
);
1370 g_object_unref (player
);
1374 swfdec_accumulate_or (GSignalInvocationHint
*ihint
, GValue
*return_accu
,
1375 const GValue
*handler_return
, gpointer data
)
1377 if (g_value_get_boolean (handler_return
))
1378 g_value_set_boolean (return_accu
, TRUE
);
1383 swfdec_player_mark_string_object (gpointer key
, gpointer value
, gpointer data
)
1385 swfdec_as_string_mark (key
);
1386 swfdec_as_object_mark (value
);
1390 swfdec_player_mark_rooted_object (gpointer object
, gpointer unused
)
1392 if (SWFDEC_IS_RESOURCE (object
)) {
1393 swfdec_resource_mark (object
);
1394 } else if (SWFDEC_IS_AS_OBJECT (object
)) {
1395 swfdec_as_object_mark (object
);
1400 swfdec_player_mark (SwfdecAsContext
*context
)
1402 SwfdecPlayer
*player
= SWFDEC_PLAYER (context
);
1404 g_hash_table_foreach (player
->registered_classes
, swfdec_player_mark_string_object
, NULL
);
1405 swfdec_as_object_mark (player
->MovieClip
);
1406 swfdec_as_object_mark (player
->Video
);
1407 g_list_foreach (player
->roots
, (GFunc
) swfdec_as_object_mark
, NULL
);
1408 g_list_foreach (player
->intervals
, (GFunc
) swfdec_as_object_mark
, NULL
);
1409 g_list_foreach (player
->rooted_objects
, swfdec_player_mark_rooted_object
, NULL
);
1411 SWFDEC_AS_CONTEXT_CLASS (swfdec_player_parent_class
)->mark (context
);
1415 swfdec_player_get_time (SwfdecAsContext
*context
, GTimeVal
*tv
)
1417 *tv
= context
->start_time
;
1419 /* FIXME: what granularity do we want? Currently it's milliseconds */
1420 g_time_val_add (tv
, SWFDEC_TICKS_TO_MSECS (SWFDEC_PLAYER (context
)->time
) * 1000);
1424 swfdec_player_check_continue (SwfdecAsContext
*context
)
1426 SwfdecPlayer
*player
= SWFDEC_PLAYER (context
);
1428 if (player
->max_runtime
== 0)
1430 return g_timer_elapsed (player
->runtime
, NULL
) * 1000 <= player
->max_runtime
;
1434 swfdec_player_class_init (SwfdecPlayerClass
*klass
)
1436 GObjectClass
*object_class
= G_OBJECT_CLASS (klass
);
1437 SwfdecAsContextClass
*context_class
= SWFDEC_AS_CONTEXT_CLASS (klass
);
1439 object_class
->get_property
= swfdec_player_get_property
;
1440 object_class
->set_property
= swfdec_player_set_property
;
1441 object_class
->dispose
= swfdec_player_dispose
;
1443 g_object_class_install_property (object_class
, PROP_INITIALIZED
,
1444 g_param_spec_boolean ("initialized", "initialized", "TRUE when the player has initialized its basic values",
1445 FALSE
, G_PARAM_READABLE
));
1446 g_object_class_install_property (object_class
, PROP_DEFAULT_WIDTH
,
1447 g_param_spec_uint ("default-width", "default width", "default width of the movie",
1448 0, G_MAXUINT
, 0, G_PARAM_READABLE
));
1449 g_object_class_install_property (object_class
, PROP_DEFAULT_HEIGHT
,
1450 g_param_spec_uint ("default-height", "default height", "default height of the movie",
1451 0, G_MAXUINT
, 0, G_PARAM_READABLE
));
1452 g_object_class_install_property (object_class
, PROP_RATE
,
1453 g_param_spec_double ("rate", "rate", "rate in frames per second",
1454 0.0, 256.0, 0.0, G_PARAM_READABLE
));
1455 g_object_class_install_property (object_class
, PROP_MOUSE_CURSOR
,
1456 g_param_spec_enum ("mouse-cursor", "mouse cursor", "how the mouse pointer should be presented",
1457 SWFDEC_TYPE_MOUSE_CURSOR
, SWFDEC_MOUSE_CURSOR_NONE
, G_PARAM_READABLE
));
1458 g_object_class_install_property (object_class
, PROP_NEXT_EVENT
,
1459 g_param_spec_long ("next-event", "next event", "how many milliseconds until the next event or 0 when no event pending",
1460 -1, G_MAXLONG
, -1, G_PARAM_READABLE
));
1461 g_object_class_install_property (object_class
, PROP_CACHE_SIZE
,
1462 g_param_spec_uint ("cache-size", "cache size", "maximum cache size in bytes",
1463 0, G_MAXUINT
, 50 * 1024 * 1024, G_PARAM_READABLE
));
1464 g_object_class_install_property (object_class
, PROP_BACKGROUND_COLOR
,
1465 g_param_spec_uint ("background-color", "background color", "ARGB color used to draw the background",
1466 0, G_MAXUINT
, SWFDEC_COLOR_COMBINE (0xFF, 0xFF, 0xFF, 0xFF), G_PARAM_READWRITE
));
1467 g_object_class_install_property (object_class
, PROP_WIDTH
,
1468 g_param_spec_int ("width", "width", "current width of the movie",
1469 -1, G_MAXINT
, -1, G_PARAM_READWRITE
));
1470 g_object_class_install_property (object_class
, PROP_HEIGHT
,
1471 g_param_spec_int ("height", "height", "current height of the movie",
1472 -1, G_MAXINT
, -1, G_PARAM_READWRITE
));
1473 g_object_class_install_property (object_class
, PROP_ALIGNMENT
,
1474 g_param_spec_enum ("alignment", "alignment", "point of the screen to align the output to",
1475 SWFDEC_TYPE_ALIGNMENT
, SWFDEC_ALIGNMENT_CENTER
, G_PARAM_READWRITE
));
1476 g_object_class_install_property (object_class
, PROP_SCALE
,
1477 g_param_spec_enum ("scale-mode", "scale mode", "method used to scale the movie",
1478 SWFDEC_TYPE_SCALE_MODE
, SWFDEC_SCALE_SHOW_ALL
, G_PARAM_READWRITE
));
1479 g_object_class_install_property (object_class
, PROP_SCALE
,
1480 g_param_spec_object ("system", "system", "object holding system information",
1481 SWFDEC_TYPE_SYSTEM
, G_PARAM_READWRITE
));
1482 g_object_class_install_property (object_class
, PROP_MAX_RUNTIME
,
1483 g_param_spec_ulong ("max-runtime", "maximum runtime", "maximum time in msecs scripts may run in the player before aborting",
1484 0, G_MAXULONG
, 10 * 1000, G_PARAM_READWRITE
));
1487 * SwfdecPlayer::invalidate:
1488 * @player: the #SwfdecPlayer affected
1489 * @extents: the smallest rectangle enclosing the full region of changes
1490 * @rectangles: a number of smaller rectangles for fine-grained control over
1492 * @n_rectangles: number of rectangles in @rectangles
1494 * This signal is emitted whenever graphical elements inside the player have
1495 * changed. It provides two ways to look at the changes: By looking at the
1496 * @extents parameter, it provides a simple way to get a single rectangle that
1497 * encloses all changes. By looking at the @rectangles array, you can get
1498 * finer control over changes which is very useful if your rendering system
1499 * provides a way to handle regions.
1501 signals
[INVALIDATE
] = g_signal_new ("invalidate", G_TYPE_FROM_CLASS (klass
),
1502 G_SIGNAL_RUN_LAST
, 0, NULL
, NULL
, swfdec_marshal_VOID__BOXED_POINTER_UINT
,
1503 G_TYPE_NONE
, 3, SWFDEC_TYPE_RECTANGLE
, G_TYPE_POINTER
, G_TYPE_UINT
);
1505 * SwfdecPlayer::advance:
1506 * @player: the #SwfdecPlayer affected
1507 * @msecs: the amount of milliseconds the player will advance
1508 * @audio_samples: number of frames the audio is advanced (in 44100Hz steps)
1510 * Emitted whenever the player advances.
1512 signals
[ADVANCE
] = g_signal_new ("advance", G_TYPE_FROM_CLASS (klass
),
1513 G_SIGNAL_RUN_LAST
, G_STRUCT_OFFSET (SwfdecPlayerClass
, advance
),
1514 NULL
, NULL
, swfdec_marshal_VOID__ULONG_UINT
,
1515 G_TYPE_NONE
, 2, G_TYPE_ULONG
, G_TYPE_UINT
);
1517 * SwfdecPlayer::handle-key:
1518 * @player: the #SwfdecPlayer affected
1519 * @key: #SwfdecKey that was pressed or released
1520 * @pressed: %TRUE if the @key was pressed or %FALSE if it was released
1522 * This signal is emitted whenever @player should respond to a key event. If
1523 * any of the handlers returns TRUE, swfdec_player_key_press() or
1524 * swfdec_player_key_release() will return TRUE. Note that unlike many event
1525 * handlers in gtk, returning TRUE will not stop further event handlers from
1526 * being invoked. Use g_signal_stop_emission() in that case.
1528 * Returns: TRUE if this handler handles the event.
1530 signals
[HANDLE_KEY
] = g_signal_new ("handle-key", G_TYPE_FROM_CLASS (klass
),
1531 G_SIGNAL_RUN_LAST
, G_STRUCT_OFFSET (SwfdecPlayerClass
, handle_key
),
1532 swfdec_accumulate_or
, NULL
, swfdec_marshal_BOOLEAN__UINT_UINT_BOOLEAN
,
1533 G_TYPE_BOOLEAN
, 3, G_TYPE_UINT
, G_TYPE_UINT
, G_TYPE_BOOLEAN
);
1535 * SwfdecPlayer::handle-mouse:
1536 * @player: the #SwfdecPlayer affected
1537 * @x: new x coordinate of the mouse
1538 * @y: new y coordinate of the mouse
1539 * @button: 1 if the button is pressed, 0 if not
1541 * This signal is emitted whenever @player should respond to a mouse event. If
1542 * any of the handlers returns TRUE, swfdec_player_handle_mouse() will return
1543 * TRUE. Note that unlike many event handlers in gtk, returning TRUE will not
1544 * stop further event handlers from being invoked. Use g_signal_stop_emission()
1547 * Returns: TRUE if this handler handles the event.
1549 signals
[HANDLE_MOUSE
] = g_signal_new ("handle-mouse", G_TYPE_FROM_CLASS (klass
),
1550 G_SIGNAL_RUN_LAST
, G_STRUCT_OFFSET (SwfdecPlayerClass
, handle_mouse
),
1551 swfdec_accumulate_or
, NULL
, swfdec_marshal_BOOLEAN__DOUBLE_DOUBLE_INT
,
1552 G_TYPE_BOOLEAN
, 3, G_TYPE_DOUBLE
, G_TYPE_DOUBLE
, G_TYPE_INT
);
1554 * SwfdecPlayer::audio-added:
1555 * @player: the #SwfdecPlayer affected
1556 * @audio: the audio stream that was added
1558 * Emitted whenever a new audio stream was added to @player.
1560 signals
[AUDIO_ADDED
] = g_signal_new ("audio-added", G_TYPE_FROM_CLASS (klass
),
1561 G_SIGNAL_RUN_LAST
, 0, NULL
, NULL
, g_cclosure_marshal_VOID__OBJECT
,
1562 G_TYPE_NONE
, 1, SWFDEC_TYPE_AUDIO
);
1564 * SwfdecPlayer::audio-removed:
1565 * @player: the #SwfdecPlayer affected
1566 * @audio: the audio stream that was removed
1568 * Emitted whenever an audio stream was removed from @player. The stream will
1569 * have been added with the SwfdecPlayer::audio-added signal previously.
1571 signals
[AUDIO_REMOVED
] = g_signal_new ("audio-removed", G_TYPE_FROM_CLASS (klass
),
1572 G_SIGNAL_RUN_LAST
, 0, NULL
, NULL
, g_cclosure_marshal_VOID__OBJECT
,
1573 G_TYPE_NONE
, 1, SWFDEC_TYPE_AUDIO
);
1575 * SwfdecPlayer::fscommand:
1576 * @player: the #SwfdecPlayer affected
1577 * @command: the command to execute. This is a lower case string.
1578 * @parameter: parameter to pass to the command. The parameter depends on the
1581 * This signal is emited whenever a Flash script command (also known as
1582 * fscommand) is encountered. This method is ued by the Flash file to
1583 * communicate with the hosting environment. In web browsers it is used to
1584 * call Javascript functions. Standalone Flash players understand a limited
1585 * set of functions. They vary from player to player, but the most common are
1586 * listed here: <itemizedlist>
1587 * <listitem><para>"quit": quits the player.</para></listitem>
1588 * <listitem><para>"fullscreen": A boolean setting (parameter is "true" or
1589 * "false") that sets the player into fullscreen mode.</para></listitem>
1590 * <listitem><para>"allowscale": A boolean setting that tells the player to
1591 * not scale the Flash application.</para></listitem>
1592 * <listitem><para>"showmenu": A boolean setting that tells the Flash player
1593 * to not show its own entries in the right-click menu.</para></listitem>
1594 * <listitem><para>"exec": Run an external executable. The parameter
1595 * specifies the path.</para></listitem>
1596 * <listitem><para>"trapallkeys": A boolean setting that tells the Flash
1597 * player to pass all key events to the Flash application instead of using it
1598 * for keyboard shortcuts or similar.</para></listitem>
1601 signals
[FSCOMMAND
] = g_signal_new ("fscommand", G_TYPE_FROM_CLASS (klass
),
1602 G_SIGNAL_RUN_LAST
, 0, NULL
, NULL
, swfdec_marshal_VOID__STRING_STRING
,
1603 G_TYPE_NONE
, 2, G_TYPE_STRING
, G_TYPE_STRING
);
1605 * SwfdecPlayer::launch:
1606 * @player: the #SwfdecPlayer affected
1607 * @request: the type of request
1609 * @target: target to load the URL into
1610 * @data: optional data to pass on with the request. Will be of mime type
1611 * application/x-www-form-urlencoded. Can be %NULL indicating no data
1614 * Emitted whenever the @player encounters an URL that should be loaded into
1615 * a target the Flash player does not recognize. In most cases this happens
1616 * when the user clicks a link in an embedded Flash movie that should open a
1618 * The effect of calling any swfdec functions on the emitting @player is undefined.
1620 signals
[LAUNCH
] = g_signal_new ("launch", G_TYPE_FROM_CLASS (klass
),
1621 G_SIGNAL_RUN_LAST
, 0, NULL
, NULL
, swfdec_marshal_VOID__ENUM_STRING_STRING_BOXED
,
1622 G_TYPE_NONE
, 4, SWFDEC_TYPE_LOADER_REQUEST
, G_TYPE_STRING
, G_TYPE_STRING
,
1623 SWFDEC_TYPE_BUFFER
);
1625 context_class
->mark
= swfdec_player_mark
;
1626 context_class
->get_time
= swfdec_player_get_time
;
1627 context_class
->check_continue
= swfdec_player_check_continue
;
1629 klass
->advance
= swfdec_player_do_advance
;
1630 klass
->handle_key
= swfdec_player_do_handle_key
;
1631 klass
->handle_mouse
= swfdec_player_do_handle_mouse
;
1635 swfdec_player_init (SwfdecPlayer
*player
)
1639 player
->system
= swfdec_system_new ();
1640 player
->registered_classes
= g_hash_table_new (g_direct_hash
, g_direct_equal
);
1642 for (i
= 0; i
< SWFDEC_PLAYER_N_ACTION_QUEUES
; i
++) {
1643 player
->actions
[i
] = swfdec_ring_buffer_new_for_type (SwfdecPlayerAction
, 16);
1645 player
->external_actions
= swfdec_ring_buffer_new_for_type (SwfdecPlayerExternalAction
, 8);
1646 player
->cache
= swfdec_cache_new (50 * 1024 * 1024); /* 100 MB */
1647 player
->bgcolor
= SWFDEC_COLOR_COMBINE (0xFF, 0xFF, 0xFF, 0xFF);
1649 player
->runtime
= g_timer_new ();
1650 g_timer_stop (player
->runtime
);
1651 player
->max_runtime
= 10 * 1000;
1652 player
->invalidations
= g_array_new (FALSE
, FALSE
, sizeof (SwfdecRectangle
));
1653 player
->mouse_visible
= TRUE
;
1654 player
->mouse_cursor
= SWFDEC_MOUSE_CURSOR_NORMAL
;
1655 player
->iterate_timeout
.callback
= swfdec_player_iterate
;
1656 player
->stage_width
= -1;
1657 player
->stage_height
= -1;
1659 swfdec_player_resource_request_init (player
);
1663 swfdec_player_stop_all_sounds (SwfdecPlayer
*player
)
1665 g_return_if_fail (SWFDEC_IS_PLAYER (player
));
1667 while (player
->audio
) {
1668 swfdec_audio_remove (player
->audio
->data
);
1673 swfdec_player_stop_sounds (SwfdecPlayer
*player
, SwfdecAudioRemoveFunc func
, gpointer data
)
1677 g_return_if_fail (SWFDEC_IS_PLAYER (player
));
1678 g_return_if_fail (func
);
1680 walk
= player
->audio
;
1682 SwfdecAudio
*audio
= walk
->data
;
1684 if (func (audio
, data
))
1685 swfdec_audio_remove (audio
);
1689 /* rect is in global coordinates */
1691 swfdec_player_invalidate (SwfdecPlayer
*player
, const SwfdecRect
*rect
)
1697 if (swfdec_rect_is_empty (rect
)) {
1698 SWFDEC_ERROR ("called with an empty rectanle. In theory this shouldn't happen.");
1699 SWFDEC_ERROR (" However, degenerate matrixes can cause this. We need a fix for that.");
1704 swfdec_player_global_to_stage (player
, &tmp
.x0
, &tmp
.y0
);
1705 swfdec_player_global_to_stage (player
, &tmp
.x1
, &tmp
.y1
);
1706 swfdec_rectangle_init_rect (&r
, &tmp
);
1707 /* FIXME: currently we clamp the rectangle to the visible area, it might
1708 * be useful to allow out-of-bounds drawing. In that case this needs to be
1710 swfdec_rectangle_intersect (&r
, &r
, &player
->stage
);
1711 if (swfdec_rectangle_is_empty (&r
))
1714 /* FIXME: get region code into swfdec? */
1715 for (i
= 0; i
< player
->invalidations
->len
; i
++) {
1716 SwfdecRectangle
*cur
= &g_array_index (player
->invalidations
, SwfdecRectangle
, i
);
1717 if (swfdec_rectangle_contains (cur
, &r
))
1719 if (swfdec_rectangle_contains (&r
, cur
)) {
1721 swfdec_rectangle_union (&player
->invalid_extents
, &player
->invalid_extents
, &r
);
1724 if (i
== player
->invalidations
->len
) {
1725 g_array_append_val (player
->invalidations
, r
);
1726 swfdec_rectangle_union (&player
->invalid_extents
, &player
->invalid_extents
, &r
);
1728 SWFDEC_DEBUG ("toplevel invalidation of %g %g %g %g - invalid region now %d %d %d %d (%u subregions)",
1729 rect
->x0
, rect
->y0
, rect
->x1
, rect
->y1
,
1730 player
->invalid_extents
.x
, player
->invalid_extents
.y
,
1731 player
->invalid_extents
.x
+ player
->invalid_extents
.width
,
1732 player
->invalid_extents
.y
+ player
->invalid_extents
.height
,
1733 player
->invalidations
->len
);
1737 * swfdec_player_get_level:
1738 * @player: a #SwfdecPlayer
1739 * @name: a name that is supposed to refer to a level
1741 * Checks if the given @name refers to a level, and if so, returns the level.
1742 * An example for such a name is "_level5". These strings are used to refer to
1743 * root movies inside the Flash player.
1745 * Returns: the level referred to by @name or -1 if none
1748 swfdec_player_get_level (SwfdecPlayer
*player
, const char *name
)
1753 g_return_val_if_fail (SWFDEC_IS_PLAYER (player
), -1);
1754 g_return_val_if_fail (name
!= NULL
, -1);
1756 /* check name starts with "_level" */
1757 if (swfdec_strncmp (SWFDEC_AS_CONTEXT (player
)->version
, name
, "_level", 6) != 0)
1760 /* extract depth from rest string (or fail if it's not a depth) */
1762 l
= strtoul (name
, &end
, 10);
1763 if (errno
!= 0 || *end
!= 0 || l
> G_MAXINT
)
1769 swfdec_player_create_movie_at_level (SwfdecPlayer
*player
, SwfdecResource
*resource
,
1775 g_return_val_if_fail (SWFDEC_IS_PLAYER (player
), NULL
);
1776 g_return_val_if_fail (level
>= 0, NULL
);
1777 g_return_val_if_fail (swfdec_player_get_movie_at_level (player
, level
) == NULL
, NULL
);
1779 /* create new root movie */
1780 s
= swfdec_as_context_give_string (SWFDEC_AS_CONTEXT (player
), g_strdup_printf ("_level%d", level
));
1781 movie
= swfdec_movie_new (player
, level
- 16384, NULL
, resource
, NULL
, s
);
1784 movie
->name
= SWFDEC_AS_STR_EMPTY
;
1785 return SWFDEC_SPRITE_MOVIE (movie
);
1789 * swfdec_player_get_movie_at_level:
1790 * @player: a #SwfdecPlayer
1791 * @level: number of the level
1793 * This function is used to look up root movies in the given @player.
1795 * Returns: the #SwfdecMovie located at the given level or %NULL if there is no
1796 * movie at that level.
1799 swfdec_player_get_movie_at_level (SwfdecPlayer
*player
, int level
)
1804 g_return_val_if_fail (SWFDEC_IS_PLAYER (player
), NULL
);
1805 g_return_val_if_fail (level
>= 0, NULL
);
1807 depth
= level
- 16384;
1809 for (walk
= player
->roots
; walk
; walk
= walk
->next
) {
1810 SwfdecMovie
*cur
= walk
->data
;
1811 if (cur
->depth
< depth
)
1813 if (cur
->depth
== depth
)
1814 return SWFDEC_SPRITE_MOVIE (cur
);
1821 swfdec_player_launch (SwfdecPlayer
*player
, SwfdecLoaderRequest request
, const char *url
,
1822 const char *target
, SwfdecBuffer
*data
)
1824 g_return_if_fail (SWFDEC_IS_PLAYER (player
));
1825 g_return_if_fail (url
!= NULL
);
1826 g_return_if_fail (target
!= NULL
);
1828 if (!g_ascii_strncasecmp (url
, "FSCommand:", strlen ("FSCommand:"))) {
1829 const char *command
= url
+ strlen ("FSCommand:");
1830 g_signal_emit (player
, signals
[FSCOMMAND
], 0, command
, target
);
1833 g_signal_emit (player
, signals
[LAUNCH
], 0, (int) request
, url
, target
, data
);
1837 * swfdec_player_initialize:
1838 * @player: a #SwfdecPlayer
1839 * @version: Flash version to use
1840 * @rate: framerate in 256th or 0 for undefined
1841 * @width: width of movie
1842 * @height: height of movie
1844 * Initializes the player to the given @version, @width, @height and @rate. If
1845 * the player is already initialized, this function does nothing.
1848 swfdec_player_initialize (SwfdecPlayer
*player
, guint version
,
1849 guint rate
, guint width
, guint height
)
1851 g_return_if_fail (SWFDEC_IS_PLAYER (player
));
1852 g_return_if_fail (rate
> 0);
1854 if (!player
->initialized
) {
1855 SwfdecAsContext
*context
= SWFDEC_AS_CONTEXT (player
);
1856 swfdec_as_context_startup (context
, version
);
1857 /* reset state for initialization */
1858 /* FIXME: have a better way to do this */
1859 if (context
->state
== SWFDEC_AS_CONTEXT_RUNNING
) {
1860 context
->state
= SWFDEC_AS_CONTEXT_NEW
;
1861 swfdec_sprite_movie_init_context (player
, version
);
1862 swfdec_video_movie_init_context (player
, version
);
1863 swfdec_net_connection_init_context (player
, version
);
1864 swfdec_net_stream_init_context (player
, version
);
1866 swfdec_as_context_run_init_script (context
, swfdec_initialize
,
1867 sizeof (swfdec_initialize
), 8);
1869 if (context
->state
== SWFDEC_AS_CONTEXT_NEW
) {
1870 context
->state
= SWFDEC_AS_CONTEXT_RUNNING
;
1871 swfdec_as_object_set_constructor (player
->roots
->data
, player
->MovieClip
);
1874 player
->initialized
= TRUE
;
1875 g_object_notify (G_OBJECT (player
), "initialized");
1877 /* FIXME: need to kick all other movies out here */
1878 swfdec_player_remove_timeout (player
, &player
->iterate_timeout
);
1881 SWFDEC_INFO ("initializing player to size %ux%u and rate %u/256", width
, height
, rate
);
1882 if (rate
!= player
->rate
) {
1883 player
->rate
= rate
;
1884 g_object_notify (G_OBJECT (player
), "rate");
1886 if (player
->width
!= width
) {
1887 player
->width
= width
;
1888 g_object_notify (G_OBJECT (player
), "default-width");
1890 if (player
->height
!= height
) {
1891 player
->height
= height
;
1892 g_object_notify (G_OBJECT (player
), "default-height");
1894 player
->internal_width
= player
->stage_width
>= 0 ? (guint
) player
->stage_width
: player
->width
;
1895 player
->internal_height
= player
->stage_height
>= 0 ? (guint
) player
->stage_height
: player
->height
;
1896 swfdec_player_update_scale (player
);
1898 player
->iterate_timeout
.timestamp
= player
->time
+ SWFDEC_TICKS_PER_SECOND
* 256 / player
->rate
/ 10;
1899 swfdec_player_add_timeout (player
, &player
->iterate_timeout
);
1900 SWFDEC_LOG ("initialized iterate timeout %p to %"G_GUINT64_FORMAT
" (now %"G_GUINT64_FORMAT
")",
1901 &player
->iterate_timeout
, player
->iterate_timeout
.timestamp
, player
->time
);
1905 * swfdec_player_get_export_class:
1906 * @player: a #SwfdecPlayer
1907 * @name: garbage-collected string naming the export
1909 * Looks up the constructor for characters that are exported using @name.
1911 * Returns: a #SwfdecAsObject naming the constructor or %NULL if none
1914 swfdec_player_get_export_class (SwfdecPlayer
*player
, const char *name
)
1916 SwfdecAsObject
*ret
;
1918 ret
= g_hash_table_lookup (player
->registered_classes
, name
);
1920 SWFDEC_LOG ("found registered class %p for %s", ret
, name
);
1923 return player
->MovieClip
;
1927 * swfdec_player_set_export_class:
1928 * @player: a #SwfdecPlayer
1929 * @name: garbage-collected string naming the export
1930 * @object: object to use as constructor or %NULL for none
1932 * Sets the constructor to be used for instances created using the object
1933 * exported with @name.
1936 swfdec_player_set_export_class (SwfdecPlayer
*player
, const char *name
, SwfdecAsObject
*object
)
1938 g_return_if_fail (SWFDEC_IS_PLAYER (player
));
1939 g_return_if_fail (name
!= NULL
);
1940 g_return_if_fail (object
== NULL
|| SWFDEC_IS_AS_OBJECT (object
));
1943 SWFDEC_LOG ("setting class %p for %s", object
, name
);
1944 g_hash_table_insert (player
->registered_classes
, (gpointer
) name
, object
);
1946 g_hash_table_remove (player
->registered_classes
, name
);
1951 * I don't like the idea of rooting arbitrary objects very much. And so far,
1952 * this API is only necessary for the objects used for loading data. So it seems
1953 * like a good idea to revisit the refcounting and GCing of resources.
1956 swfdec_player_root_object (SwfdecPlayer
*player
, GObject
*object
)
1958 g_return_if_fail (SWFDEC_IS_PLAYER (player
));
1959 g_return_if_fail (G_IS_OBJECT (object
));
1961 g_object_ref (object
);
1962 player
->rooted_objects
= g_list_prepend (player
->rooted_objects
, object
);
1966 swfdec_player_unroot_object (SwfdecPlayer
*player
, GObject
*object
)
1970 g_return_if_fail (SWFDEC_IS_PLAYER (player
));
1971 g_return_if_fail (G_IS_OBJECT (object
));
1972 entry
= g_list_find (player
->rooted_objects
, object
);
1973 g_return_if_fail (entry
!= NULL
);
1974 g_object_unref (object
);
1975 player
->rooted_objects
= g_list_delete_link (player
->rooted_objects
, entry
);
1981 * swfdec_player_new:
1982 * @debugger: %NULL or a #SwfdecAsDebugger to use for debugging this player.
1984 * Creates a new player. This function is supposed to be used for testing.
1985 * Because of this, the created player will behave as predictable as possible.
1986 * For example, it will generate the same random number sequence every time.
1987 * The function calls swfdec_init () for you if it wasn't called before.
1989 * Returns: The new player
1992 swfdec_player_new (SwfdecAsDebugger
*debugger
)
1994 static const GTimeVal the_beginning
= { 1035840244, 0 };
1995 SwfdecPlayer
*player
;
1997 g_return_val_if_fail (debugger
== NULL
|| SWFDEC_IS_AS_DEBUGGER (debugger
), NULL
);
2000 player
= g_object_new (SWFDEC_TYPE_PLAYER
, "random-seed", 0,
2002 "debugger", debugger
, NULL
);
2003 /* FIXME: make this a property or something and don't set it here */
2004 SWFDEC_AS_CONTEXT (player
)->start_time
= the_beginning
;
2010 * swfdec_player_set_loader:
2011 * @player: a #SwfdecPlayer
2012 * @loader: the loader to use for this player. Takes ownership of the given loader.
2014 * Sets the loader for the main data. This function only works if no loader has
2015 * been set on @player yet.
2016 * For details, see swfdec_player_set_loader_with_variables().
2019 swfdec_player_set_loader (SwfdecPlayer
*player
, SwfdecLoader
*loader
)
2021 g_return_if_fail (SWFDEC_IS_PLAYER (player
));
2022 g_return_if_fail (player
->roots
== NULL
);
2023 g_return_if_fail (SWFDEC_IS_LOADER (loader
));
2025 swfdec_player_set_loader_with_variables (player
, loader
, NULL
);
2029 * swfdec_player_set_loader_with_variables:
2030 * @player: a #SwfdecPlayer
2031 * @loader: the loader to use for this player. Takes ownership of the given loader.
2032 * @variables: a string that is checked to be in 'application/x-www-form-urlencoded'
2033 * syntax describing the arguments to set on the new player or NULL for
2036 * Sets the loader for the main data. This function only works if no loader has
2037 * been set on @player yet.
2038 * If the @variables are set and validate, they will be set as properties on the
2042 swfdec_player_set_loader_with_variables (SwfdecPlayer
*player
, SwfdecLoader
*loader
,
2043 const char *variables
)
2047 g_return_if_fail (SWFDEC_IS_PLAYER (player
));
2048 g_return_if_fail (player
->resource
== NULL
);
2049 g_return_if_fail (SWFDEC_IS_LOADER (loader
));
2051 player
->resource
= swfdec_resource_new (player
, loader
, variables
);
2052 movie
= swfdec_movie_new (player
, -16384, NULL
, player
->resource
, NULL
, SWFDEC_AS_STR__level0
);
2053 movie
->name
= SWFDEC_AS_STR_EMPTY
;
2054 g_object_unref (loader
);
2058 * swfdec_player_new_from_file:
2059 * @filename: name of the file to play
2061 * Creates a player to play back the given file. If the file does not
2062 * exist or another error occurs, the player will be in an error state and not
2064 * This function calls swfdec_init () for you if it wasn't called before.
2066 * Returns: a new player
2069 swfdec_player_new_from_file (const char *filename
)
2071 SwfdecLoader
*loader
;
2072 SwfdecPlayer
*player
;
2074 g_return_val_if_fail (filename
!= NULL
, NULL
);
2076 loader
= swfdec_file_loader_new (filename
);
2077 player
= swfdec_player_new (NULL
);
2078 swfdec_player_set_loader (player
, loader
);
2086 * Initializes the Swfdec library.
2091 static gboolean _inited
= FALSE
;
2099 if (!g_thread_supported ())
2100 g_thread_init (NULL
);
2104 s
= g_getenv ("SWFDEC_DEBUG");
2109 level
= strtoul (s
, &end
, 0);
2111 swfdec_debug_set_level (level
);
2117 * swfdec_player_handle_mouse:
2118 * @player: a #SwfdecPlayer
2119 * @x: x coordinate of mouse
2120 * @y: y coordinate of mouse
2121 * @button: 1 for pressed, 0 for not pressed
2123 * Updates the current mouse status. If the mouse has left the area of @player,
2124 * you should pass values outside the movie size for @x and @y. You will
2125 * probably want to call swfdec_player_advance() before to update the player to
2126 * the correct time when calling this function.
2128 * Returns: %TRUE if the mouse event was handled. %FALSE to propagate the event
2129 * further. A mouse event may not be handled if the user clicked on a
2133 swfdec_player_handle_mouse (SwfdecPlayer
*player
,
2134 double x
, double y
, int button
)
2138 g_return_val_if_fail (SWFDEC_IS_PLAYER (player
), FALSE
);
2139 g_return_val_if_fail (button
== 0 || button
== 1, FALSE
);
2141 g_signal_emit (player
, signals
[HANDLE_MOUSE
], 0, x
, y
, button
, &ret
);
2147 * swfdec_player_key_press:
2148 * @player: a #SwfdecPlayer
2149 * @keycode: the key that was pressed
2150 * @character: UCS4 of the character that was inserted or 0 if none
2152 * Call this function to make the @player react to a key press. Be sure to
2153 * check that keycode transformations are done correctly. For a list of
2154 * keycodes see FIXME.
2156 * Returns: %TRUE if the key press was handled by the @player, %FALSE if it
2157 * should be propagated further
2160 swfdec_player_key_press (SwfdecPlayer
*player
, guint keycode
, guint character
)
2164 g_return_val_if_fail (SWFDEC_IS_PLAYER (player
), FALSE
);
2165 g_return_val_if_fail (keycode
< 256, FALSE
);
2167 g_signal_emit (player
, signals
[HANDLE_KEY
], 0, keycode
, character
, TRUE
, &ret
);
2173 * swfdec_player_key_release:
2174 * @player: a #SwfdecPlayer
2175 * @keycode: the key that was released
2176 * @character: UCS4 of the character that was inserted or 0 if none
2178 * Call this function to make the @player react to a key being released. See
2179 * swfdec_player_key_press() for details.
2181 * Returns: %TRUE if the key press was handled by the @player, %FALSE if it
2182 * should be propagated further
2185 swfdec_player_key_release (SwfdecPlayer
*player
, guint keycode
, guint character
)
2189 g_return_val_if_fail (SWFDEC_IS_PLAYER (player
), FALSE
);
2190 g_return_val_if_fail (keycode
< 256, FALSE
);
2192 g_signal_emit (player
, signals
[HANDLE_KEY
], 0, keycode
, character
, FALSE
, &ret
);
2198 * swfdec_player_render:
2199 * @player: a #SwfdecPlayer
2200 * @cr: #cairo_t to render to
2201 * @x: x coordinate of top left position to render
2202 * @y: y coordinate of top left position to render
2203 * @width: width of area to render or 0 for full width
2204 * @height: height of area to render or 0 for full height
2206 * Renders the given area of the current frame to @cr.
2209 swfdec_player_render (SwfdecPlayer
*player
, cairo_t
*cr
,
2210 double x
, double y
, double width
, double height
)
2212 static const SwfdecColorTransform trans
= { 256, 0, 256, 0, 256, 0, 256, 0 };
2216 g_return_if_fail (SWFDEC_IS_PLAYER (player
));
2217 g_return_if_fail (cr
!= NULL
);
2218 g_return_if_fail (width
>= 0.0);
2219 g_return_if_fail (height
>= 0.0);
2221 /* FIXME: fail when !initialized? */
2222 if (!swfdec_player_is_initialized (player
))
2226 width
= player
->stage_width
;
2228 height
= player
->stage_height
;
2231 cairo_rectangle (cr
, x
, y
, width
, height
);
2233 /* compute the rectangle */
2234 x
-= player
->offset_x
;
2235 y
-= player
->offset_y
;
2236 real
.x0
= floor (x
* SWFDEC_TWIPS_SCALE_FACTOR
) / player
->scale_x
;
2237 real
.y0
= floor (y
* SWFDEC_TWIPS_SCALE_FACTOR
) / player
->scale_y
;
2238 real
.x1
= ceil ((x
+ width
) * SWFDEC_TWIPS_SCALE_FACTOR
) / player
->scale_x
;
2239 real
.y1
= ceil ((y
+ height
) * SWFDEC_TWIPS_SCALE_FACTOR
) / player
->scale_y
;
2240 SWFDEC_INFO ("=== %p: START RENDER, area %g %g %g %g ===", player
,
2241 real
.x0
, real
.y0
, real
.x1
, real
.y1
);
2242 /* convert the cairo matrix */
2243 cairo_translate (cr
, player
->offset_x
, player
->offset_y
);
2244 cairo_scale (cr
, player
->scale_x
/ SWFDEC_TWIPS_SCALE_FACTOR
, player
->scale_y
/ SWFDEC_TWIPS_SCALE_FACTOR
);
2245 swfdec_color_set_source (cr
, player
->bgcolor
);
2248 for (walk
= player
->roots
; walk
; walk
= walk
->next
) {
2249 swfdec_movie_render (walk
->data
, cr
, &trans
, &real
);
2251 SWFDEC_INFO ("=== %p: END RENDER ===", player
);
2256 * swfdec_player_advance:
2257 * @player: the #SwfdecPlayer to advance
2258 * @msecs: number of milliseconds to advance
2260 * Advances @player by @msecs. You should make sure to call this function as
2261 * often as the SwfdecPlayer::next-event property indicates.
2264 swfdec_player_advance (SwfdecPlayer
*player
, gulong msecs
)
2267 g_return_if_fail (SWFDEC_IS_PLAYER (player
));
2269 frames
= SWFDEC_TICKS_TO_SAMPLES (player
->time
+ SWFDEC_MSECS_TO_TICKS (msecs
))
2270 - SWFDEC_TICKS_TO_SAMPLES (player
->time
);
2271 g_signal_emit (player
, signals
[ADVANCE
], 0, msecs
, frames
);
2275 * swfdec_player_is_initialized:
2276 * @player: a #SwfdecPlayer
2278 * Determines if the @player is initalized yet. An initialized player is able
2279 * to provide basic values like width, height or rate. A player may not be
2280 * initialized if the loader it was started with does not reference a Flash
2281 * resources or it did not provide enough data yet. If a player is initialized,
2282 * it will never be uninitialized again.
2284 * Returns: TRUE if the basic values are known.
2287 swfdec_player_is_initialized (SwfdecPlayer
*player
)
2289 g_return_val_if_fail (SWFDEC_IS_PLAYER (player
), FALSE
);
2291 return player
->initialized
;
2295 * swfdec_player_get_next_event:
2296 * @player: ia #SwfdecPlayer
2298 * Queries how long to the next event. This is the next time when you should
2299 * call swfdec_player_advance() to forward to.
2301 * Returns: number of milliseconds until next event or -1 if no outstanding event
2304 swfdec_player_get_next_event (SwfdecPlayer
*player
)
2309 g_return_val_if_fail (SWFDEC_IS_PLAYER (player
), 0);
2311 if (swfdec_as_context_is_aborted (SWFDEC_AS_CONTEXT (player
)))
2314 tick
= swfdec_player_get_next_event_time (player
);
2315 if (tick
== G_MAXUINT64
)
2317 /* round up to full msecs */
2318 ret
= SWFDEC_TICKS_TO_MSECS (tick
+ SWFDEC_TICKS_PER_SECOND
/ 1000 - 1);
2324 * swfdec_player_get_rate:
2325 * @player: a #SwfdecPlayer
2327 * Queries the framerate of this movie. This number specifies the number
2328 * of frames that are supposed to pass per second. It is a
2329 * multiple of 1/256. It is possible that the movie has no framerate if it does
2330 * not display a Flash movie but an FLV video for example. This does not mean
2331 * it will not change however.
2333 * Returns: The framerate of this movie or 0 if it isn't known yet or the
2334 * movie doesn't have a framerate.
2337 swfdec_player_get_rate (SwfdecPlayer
*player
)
2339 g_return_val_if_fail (SWFDEC_IS_PLAYER (player
), 0.0);
2341 return player
->rate
/ 256.0;
2345 * swfdec_player_get_default_size:
2346 * @player: a #SwfdecPlayer
2347 * @width: integer to store the width in or %NULL
2348 * @height: integer to store the height in or %NULL
2350 * If the default size of the movie is initialized, fills in @width and @height
2351 * with the size. Otherwise @width and @height are set to 0.
2354 swfdec_player_get_default_size (SwfdecPlayer
*player
, guint
*width
, guint
*height
)
2356 g_return_if_fail (SWFDEC_IS_PLAYER (player
));
2359 *width
= player
->width
;
2361 *height
= player
->height
;
2365 * swfdec_player_get_size:
2366 * @player: a #SwfdecPlayer
2367 * @width: integer to store the width in or %NULL
2368 * @height: integer to store the height in or %NULL
2370 * Gets the currently set image size. If the default width or height should be
2371 * used, the width or height respectively is set to -1.
2374 swfdec_player_get_size (SwfdecPlayer
*player
, int *width
, int *height
)
2376 g_return_if_fail (SWFDEC_IS_PLAYER (player
));
2379 *width
= player
->stage_width
;
2381 *height
= player
->stage_height
;
2385 swfdec_player_update_size (gpointer playerp
, gpointer unused
)
2387 SwfdecPlayer
*player
= playerp
;
2388 guint width
, height
;
2390 /* FIXME: only update if not fullscreen */
2391 width
= player
->stage_width
>=0 ? (guint
) player
->stage_width
: player
->width
;
2392 height
= player
->stage_height
>=0 ? (guint
) player
->stage_height
: player
->height
;
2393 /* only broadcast once */
2394 if (width
== player
->internal_width
&& height
== player
->internal_height
)
2397 player
->internal_width
= width
;
2398 player
->internal_height
= height
;
2399 if (player
->scale_mode
== SWFDEC_SCALE_NONE
)
2400 swfdec_player_broadcast (player
, SWFDEC_AS_STR_Stage
, SWFDEC_AS_STR_onResize
);
2404 * swfdec_player_set_size:
2405 * @player: a #SwfdecPlayer
2406 * @width: desired width of the movie or -1 for default
2407 * @height: desired height of the movie or -1 for default
2409 * Sets the image size to the given values. The image size is what the area that
2410 * the @player will render and advocate with scripts.
2413 swfdec_player_set_size (SwfdecPlayer
*player
, int width
, int height
)
2415 gboolean changed
= FALSE
;
2417 g_return_if_fail (SWFDEC_IS_PLAYER (player
));
2418 g_return_if_fail (width
>= -1);
2419 g_return_if_fail (height
>= -1);
2421 if (player
->stage_width
!= width
) {
2422 player
->stage_width
= width
;
2423 g_object_notify (G_OBJECT (player
), "width");
2426 if (player
->stage_height
!= height
) {
2427 player
->stage_height
= height
;
2428 g_object_notify (G_OBJECT (player
), "height");
2431 swfdec_player_update_scale (player
);
2433 swfdec_player_add_external_action (player
, player
, swfdec_player_update_size
, NULL
);
2437 * swfdec_player_get_audio:
2438 * @player: a #SwfdecPlayer
2440 * Returns a list of all currently active audio streams in @player.
2442 * Returns: A #GList of #SwfdecAudio. You must not modify or free this list.
2444 /* FIXME: I don't like this function */
2446 swfdec_player_get_audio (SwfdecPlayer
* player
)
2448 g_return_val_if_fail (SWFDEC_IS_PLAYER (player
), NULL
);
2450 return player
->audio
;
2454 * swfdec_player_get_background_color:
2455 * @player: a #SwfdecPlayer
2457 * Gets the current background color. The color will be an ARGB-quad, with the
2458 * MSB being the alpha value.
2460 * Returns: the background color as an ARGB value
2463 swfdec_player_get_background_color (SwfdecPlayer
*player
)
2465 g_return_val_if_fail (SWFDEC_IS_PLAYER (player
), SWFDEC_COLOR_COMBINE (0xFF, 0xFF, 0xFF, 0xFF));
2467 return player
->bgcolor
;
2471 * swfdec_player_set_background_color:
2472 * @player: a #SwfdecPlayer
2473 * @color: new color to use as background color
2475 * Sets a new background color as an ARGB value. To get transparency, set the
2476 * value to 0. To get a black beackground, use 0xFF000000.
2479 swfdec_player_set_background_color (SwfdecPlayer
*player
, guint color
)
2481 g_return_if_fail (SWFDEC_IS_PLAYER (player
));
2483 player
->bgcolor_set
= TRUE
;
2484 if (player
->bgcolor
== color
)
2486 player
->bgcolor
= color
;
2487 g_object_notify (G_OBJECT (player
), "background-color");
2488 if (swfdec_player_is_initialized (player
)) {
2489 g_signal_emit (player
, signals
[INVALIDATE
], 0, 0.0, 0.0,
2490 (double) player
->width
, (double) player
->height
);
2495 * swfdec_player_get_scale_mode:
2496 * @player: a #SwfdecPlayer
2498 * Gets the currrent mode used for scaling the movie. See #SwfdecScaleMode for
2499 * the different modes.
2501 * Returns: the current scale mode
2504 swfdec_player_get_scale_mode (SwfdecPlayer
*player
)
2506 g_return_val_if_fail (SWFDEC_IS_PLAYER (player
), SWFDEC_SCALE_SHOW_ALL
);
2508 return player
->scale_mode
;
2512 * swfdec_player_set_scale_mode:
2513 * @player: a #SwfdecPlayer
2514 * @mode: a #SwfdecScaleMode
2516 * Sets the currrent mode used for scaling the movie. See #SwfdecScaleMode for
2517 * the different modes.
2520 swfdec_player_set_scale_mode (SwfdecPlayer
*player
, SwfdecScaleMode mode
)
2522 g_return_if_fail (SWFDEC_IS_PLAYER (player
));
2524 if (player
->scale_mode
!= mode
) {
2525 player
->scale_mode
= mode
;
2526 swfdec_player_update_scale (player
);
2527 g_object_notify (G_OBJECT (player
), "scale-mode");
2532 * swfdec_player_get_alignment:
2533 * @player: a #SwfdecPlayer
2535 * Gets the alignment of the player. The alignment describes what point is used
2536 * as the anchor for drawing the contents. See #SwfdecAlignment for possible
2539 * Returns: the current alignment
2542 swfdec_player_get_alignment (SwfdecPlayer
*player
)
2544 g_return_val_if_fail (SWFDEC_IS_PLAYER (player
), SWFDEC_ALIGNMENT_CENTER
);
2546 return swfdec_player_alignment_from_flags (player
->align_flags
);
2550 * swfdec_player_set_alignment:
2551 * @player: a #SwfdecPlayer
2552 * @align: #SwfdecAlignment to set
2554 * Sets the alignment to @align. For details about alignment, see
2555 * swfdec_player_get_alignment() and #SwfdecAlignment.
2558 swfdec_player_set_alignment (SwfdecPlayer
*player
, SwfdecAlignment align
)
2562 g_return_if_fail (SWFDEC_IS_PLAYER (player
));
2564 flags
= swfdec_player_alignment_to_flags (align
);
2565 swfdec_player_set_align_flags (player
, flags
);
2569 swfdec_player_set_align_flags (SwfdecPlayer
*player
, guint flags
)
2571 g_return_if_fail (SWFDEC_IS_PLAYER (player
));
2573 if (flags
!= player
->align_flags
) {
2574 player
->align_flags
= flags
;
2575 swfdec_player_update_scale (player
);
2576 g_object_notify (G_OBJECT (player
), "alignment");
2581 * swfdec_player_get_maximum_runtime:
2582 * @player: a #SwfdecPlayer
2584 * Queries the given @player for how long scripts may run. see
2585 * swfdec_player_set_maximum_runtime() for a longer discussion of this value.
2587 * Returns: the maximum time in milliseconds that scripts are allowed to run or
2591 swfdec_player_get_maximum_runtime (SwfdecPlayer
*player
)
2593 g_return_val_if_fail (SWFDEC_IS_PLAYER (player
), 0);
2595 return player
->max_runtime
;
2599 * swfdec_player_set_maximum_runtime:
2600 * @player: a #SwfdecPlayer
2601 * @msecs: time in milliseconds that scripts are allowed to run or 0 for
2604 * Sets the time that the player may use to let internal scripts run. If the
2605 * Flash file that is currently played back does not manage to complete its
2606 * scripts in the given time, it is aborted. You cannot continue the scripts at
2607 * a later point in time. However, your application may become unresponsive and
2608 * your users annoyed if they cannot interact with it for too long. To give a
2609 * reference point, the Adobe Flash player usually sets this value to 10
2610 * seconds. Note that this time determines the maximum time calling
2611 * swfdec_player_advance() may take, even if it is called with a large value.
2612 * Also note that this setting is ignored when running inside a debugger.
2615 swfdec_player_set_maximum_runtime (SwfdecPlayer
*player
, gulong msecs
)
2617 g_return_if_fail (SWFDEC_IS_PLAYER (player
));
2619 player
->max_runtime
= msecs
;
2620 g_object_notify (G_OBJECT (player
), "max-runtime");