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
) + 1; 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 if (swfdec_ring_buffer_get_size (player
->actions
[importance
]) >= 256) {
371 swfdec_player_compress_actions (player
->actions
[importance
]);
372 action
= swfdec_ring_buffer_push (player
->actions
[importance
]);
373 /* if it doesn't get smaller, bail */
374 if (action
== NULL
) {
375 swfdec_as_context_abort (SWFDEC_AS_CONTEXT (player
),
376 "256 levels of recursion were exceeded in one action list.");
380 swfdec_ring_buffer_set_size (player
->actions
[importance
],
381 swfdec_ring_buffer_get_size (player
->actions
[importance
]) + 16);
382 action
= swfdec_ring_buffer_push (player
->actions
[importance
]);
390 * swfdec_player_add_event:
391 * @player: a #SwfdecPlayer
392 * @movie: the movie on which to trigger the event
393 * @type: type of the event
394 * @importance: importance of the event
396 * Adds an action to the @player. Actions are used by Flash player to solve
397 * reentrancy issues. Instead of calling back into the Actionscript engine,
398 * an action is queued for later execution. So if you're writing code that
399 * is calling Actionscript code, you want to do this by using actions.
402 swfdec_player_add_action (SwfdecPlayer
*player
, SwfdecMovie
*movie
, SwfdecEventType type
,
405 SwfdecPlayerAction action
= { movie
, NULL
, type
};
407 g_return_if_fail (SWFDEC_IS_PLAYER (player
));
408 g_return_if_fail (SWFDEC_IS_MOVIE (movie
));
409 g_return_if_fail (importance
< SWFDEC_PLAYER_N_ACTION_QUEUES
);
411 SWFDEC_LOG ("adding action %s %u", movie
->name
, type
);
412 swfdec_player_do_add_action (player
, importance
, &action
);
416 swfdec_player_add_action_script (SwfdecPlayer
*player
, SwfdecMovie
*movie
,
417 SwfdecScript
*script
, guint importance
)
419 SwfdecPlayerAction action
= { movie
, script
, 0 };
421 g_return_if_fail (SWFDEC_IS_PLAYER (player
));
422 g_return_if_fail (SWFDEC_IS_MOVIE (movie
));
423 g_return_if_fail (script
!= NULL
);
424 g_return_if_fail (importance
< SWFDEC_PLAYER_N_ACTION_QUEUES
);
426 SWFDEC_LOG ("adding action script %s %s", movie
->name
, script
->name
);
427 swfdec_player_do_add_action (player
, importance
, &action
);
431 * swfdec_player_remove_all_actions:
432 * @player: a #SwfdecPlayer
433 * @movie: movie pointer identifying the actions to be removed
435 * Removes all actions associated with @movie that have not yet been executed.
436 * See swfdec_player_add_action() for details about actions.
439 swfdec_player_remove_all_actions (SwfdecPlayer
*player
, SwfdecMovie
*movie
)
441 SwfdecPlayerAction
*action
;
444 g_return_if_fail (SWFDEC_IS_PLAYER (player
));
445 g_return_if_fail (SWFDEC_IS_MOVIE (movie
));
447 for (i
= 0; i
< SWFDEC_PLAYER_N_ACTION_QUEUES
; i
++) {
448 for (j
= 0; j
< swfdec_ring_buffer_get_n_elements (player
->actions
[i
]); j
++) {
449 action
= swfdec_ring_buffer_peek_nth (player
->actions
[i
], j
);
451 if (action
->movie
== movie
) {
452 SWFDEC_LOG ("removing action %p %u",
453 action
->movie
, action
->event
);
454 action
->movie
= NULL
;
461 swfdec_player_do_action (SwfdecPlayer
*player
)
463 SwfdecPlayerAction
*action
;
466 for (i
= 0; i
< SWFDEC_PLAYER_N_ACTION_QUEUES
; i
++) {
468 action
= swfdec_ring_buffer_pop (player
->actions
[i
]);
471 } while (action
->movie
== NULL
); /* skip removed actions */
473 if (action
->script
) {
474 swfdec_as_object_run_with_security (SWFDEC_AS_OBJECT (action
->movie
),
475 action
->script
, SWFDEC_SECURITY (action
->movie
->resource
));
477 swfdec_movie_execute (action
->movie
, action
->event
);
487 swfdec_player_perform_external_actions (SwfdecPlayer
*player
)
489 SwfdecPlayerExternalAction
*action
;
492 /* remove timeout if it exists - do this before executing stuff below */
493 if (player
->external_timeout
.callback
) {
494 swfdec_player_remove_timeout (player
, &player
->external_timeout
);
495 player
->external_timeout
.callback
= NULL
;
498 /* we need to query the number of current actions so newly added ones aren't
499 * executed in here */
500 for (i
= swfdec_ring_buffer_get_n_elements (player
->external_actions
); i
> 0; i
--) {
501 action
= swfdec_ring_buffer_pop (player
->external_actions
);
502 g_assert (action
!= NULL
);
503 /* skip removed actions */
504 if (action
->object
== NULL
)
506 action
->func (action
->object
, action
->data
);
507 swfdec_player_perform_actions (player
);
512 swfdec_player_trigger_external_actions (SwfdecTimeout
*advance
)
514 SwfdecPlayer
*player
= SWFDEC_PLAYER ((guint8
*) advance
- G_STRUCT_OFFSET (SwfdecPlayer
, external_timeout
));
516 player
->external_timeout
.callback
= NULL
;
517 swfdec_player_perform_external_actions (player
);
521 swfdec_player_add_external_action (SwfdecPlayer
*player
, gpointer object
,
522 SwfdecActionFunc action_func
, gpointer action_data
)
524 SwfdecPlayerExternalAction
*action
;
526 g_return_if_fail (SWFDEC_IS_PLAYER (player
));
527 g_return_if_fail (object
!= NULL
);
528 g_return_if_fail (action_func
!= NULL
);
530 SWFDEC_LOG ("adding external action %p %p %p", object
, action_func
, action_data
);
531 action
= swfdec_ring_buffer_push (player
->external_actions
);
532 if (action
== NULL
) {
533 /* FIXME: limit number of actions to not get inf loops due to scripts? */
534 swfdec_ring_buffer_set_size (player
->external_actions
,
535 swfdec_ring_buffer_get_size (player
->external_actions
) + 16);
536 action
= swfdec_ring_buffer_push (player
->external_actions
);
539 action
->object
= object
;
540 action
->func
= action_func
;
541 action
->data
= action_data
;
542 if (!player
->external_timeout
.callback
) {
543 /* trigger execution immediately.
544 * But if initialized, keep at least 100ms from when the last external
545 * timeout triggered. This is a crude method to get around infinite loops
546 * when script actions executed by external actions trigger another external
547 * action that would execute instantly.
549 if (player
->initialized
) {
550 player
->external_timeout
.timestamp
= MAX (player
->time
,
551 player
->external_timeout
.timestamp
+ SWFDEC_MSECS_TO_TICKS (100));
553 player
->external_timeout
.timestamp
= player
->time
;
555 player
->external_timeout
.callback
= swfdec_player_trigger_external_actions
;
556 swfdec_player_add_timeout (player
, &player
->external_timeout
);
561 swfdec_player_remove_all_external_actions (SwfdecPlayer
*player
, gpointer object
)
563 SwfdecPlayerExternalAction
*action
;
566 g_return_if_fail (SWFDEC_IS_PLAYER (player
));
567 g_return_if_fail (object
!= NULL
);
569 for (i
= 0; i
< swfdec_ring_buffer_get_n_elements (player
->external_actions
); i
++) {
570 action
= swfdec_ring_buffer_peek_nth (player
->external_actions
, i
);
572 if (action
->object
== object
) {
573 SWFDEC_LOG ("removing external action %p %p %p",
574 action
->object
, action
->func
, action
->data
);
575 action
->object
= NULL
;
580 /*** SwfdecPlayer ***/
594 static guint signals
[LAST_SIGNAL
] = { 0, };
605 PROP_BACKGROUND_COLOR
,
614 G_DEFINE_TYPE (SwfdecPlayer
, swfdec_player
, SWFDEC_TYPE_AS_CONTEXT
)
617 swfdec_player_remove_movie (SwfdecPlayer
*player
, SwfdecMovie
*movie
)
619 swfdec_movie_remove (movie
);
620 player
->movies
= g_list_remove (player
->movies
, movie
);
624 swfdec_player_alignment_to_flags (SwfdecAlignment alignment
)
626 static const guint align_flags
[9] = {
627 SWFDEC_ALIGN_FLAG_TOP
| SWFDEC_ALIGN_FLAG_LEFT
,
628 SWFDEC_ALIGN_FLAG_TOP
,
629 SWFDEC_ALIGN_FLAG_TOP
| SWFDEC_ALIGN_FLAG_RIGHT
,
630 SWFDEC_ALIGN_FLAG_LEFT
,
632 SWFDEC_ALIGN_FLAG_RIGHT
,
633 SWFDEC_ALIGN_FLAG_BOTTOM
| SWFDEC_ALIGN_FLAG_LEFT
,
634 SWFDEC_ALIGN_FLAG_BOTTOM
,
635 SWFDEC_ALIGN_FLAG_BOTTOM
| SWFDEC_ALIGN_FLAG_RIGHT
637 return align_flags
[alignment
];
640 static SwfdecAlignment
641 swfdec_player_alignment_from_flags (guint flags
)
643 if (flags
& SWFDEC_ALIGN_FLAG_TOP
) {
644 if (flags
& SWFDEC_ALIGN_FLAG_LEFT
) {
645 return SWFDEC_ALIGNMENT_TOP_LEFT
;
646 } else if (flags
& SWFDEC_ALIGN_FLAG_RIGHT
) {
647 return SWFDEC_ALIGNMENT_TOP_RIGHT
;
649 return SWFDEC_ALIGNMENT_TOP
;
651 } else if (flags
& SWFDEC_ALIGN_FLAG_BOTTOM
) {
652 if (flags
& SWFDEC_ALIGN_FLAG_LEFT
) {
653 return SWFDEC_ALIGNMENT_BOTTOM_LEFT
;
654 } else if (flags
& SWFDEC_ALIGN_FLAG_RIGHT
) {
655 return SWFDEC_ALIGNMENT_BOTTOM_RIGHT
;
657 return SWFDEC_ALIGNMENT_BOTTOM
;
660 if (flags
& SWFDEC_ALIGN_FLAG_LEFT
) {
661 return SWFDEC_ALIGNMENT_LEFT
;
662 } else if (flags
& SWFDEC_ALIGN_FLAG_RIGHT
) {
663 return SWFDEC_ALIGNMENT_RIGHT
;
665 return SWFDEC_ALIGNMENT_CENTER
;
671 swfdec_player_get_property (GObject
*object
, guint param_id
, GValue
*value
,
674 SwfdecPlayer
*player
= SWFDEC_PLAYER (object
);
677 case PROP_BACKGROUND_COLOR
:
678 g_value_set_uint (value
, swfdec_player_get_background_color (player
));
680 case PROP_CACHE_SIZE
:
681 g_value_set_uint (value
, player
->cache
->max_size
);
683 case PROP_INITIALIZED
:
684 g_value_set_boolean (value
, swfdec_player_is_initialized (player
));
686 case PROP_DEFAULT_WIDTH
:
687 g_value_set_uint (value
, player
->width
);
689 case PROP_DEFAULT_HEIGHT
:
690 g_value_set_uint (value
, player
->height
);
693 g_value_set_double (value
, player
->rate
/ 256.0);
695 case PROP_MOUSE_CURSOR
:
696 g_value_set_enum (value
, player
->mouse_cursor
);
698 case PROP_NEXT_EVENT
:
699 g_value_set_uint (value
, swfdec_player_get_next_event (player
));
702 g_value_set_int (value
, player
->stage_width
);
705 g_value_set_int (value
, player
->stage_height
);
708 g_value_set_enum (value
, swfdec_player_alignment_from_flags (player
->align_flags
));
711 g_value_set_enum (value
, player
->scale_mode
);
714 g_value_set_object (value
, player
->system
);
716 case PROP_MAX_RUNTIME
:
717 g_value_set_ulong (value
, player
->max_runtime
);
720 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, param_id
, pspec
);
726 swfdec_player_update_scale (SwfdecPlayer
*player
)
729 double scale_x
, scale_y
;
731 player
->stage
.width
= player
->stage_width
>= 0 ? player
->stage_width
: (int) player
->width
;
732 player
->stage
.height
= player
->stage_height
>= 0 ? player
->stage_height
: (int) player
->height
;
733 if (player
->stage
.height
== 0 || player
->stage
.width
== 0) {
734 player
->scale_x
= 1.0;
735 player
->scale_y
= 1.0;
736 player
->offset_x
= 0;
737 player
->offset_y
= 0;
740 if (player
->width
== 0 || player
->height
== 0) {
744 scale_x
= (double) player
->stage
.width
/ player
->width
;
745 scale_y
= (double) player
->stage
.height
/ player
->height
;
747 switch (player
->scale_mode
) {
748 case SWFDEC_SCALE_SHOW_ALL
:
749 player
->scale_x
= MIN (scale_x
, scale_y
);
750 player
->scale_y
= player
->scale_x
;
752 case SWFDEC_SCALE_NO_BORDER
:
753 player
->scale_x
= MAX (scale_x
, scale_y
);
754 player
->scale_y
= player
->scale_x
;
756 case SWFDEC_SCALE_EXACT_FIT
:
757 player
->scale_x
= scale_x
;
758 player
->scale_y
= scale_y
;
760 case SWFDEC_SCALE_NONE
:
761 player
->scale_x
= 1.0;
762 player
->scale_y
= 1.0;
765 g_assert_not_reached ();
767 width
= player
->stage
.width
- ceil (player
->width
* player
->scale_x
);
768 height
= player
->stage
.height
- ceil (player
->height
* player
->scale_y
);
769 if (player
->align_flags
& SWFDEC_ALIGN_FLAG_LEFT
) {
770 player
->offset_x
= 0;
771 } else if (player
->align_flags
& SWFDEC_ALIGN_FLAG_RIGHT
) {
772 player
->offset_x
= width
;
774 player
->offset_x
= width
/ 2;
776 if (player
->align_flags
& SWFDEC_ALIGN_FLAG_TOP
) {
777 player
->offset_y
= 0;
778 } else if (player
->align_flags
& SWFDEC_ALIGN_FLAG_BOTTOM
) {
779 player
->offset_y
= height
;
781 player
->offset_y
= height
/ 2;
783 SWFDEC_LOG ("coordinate translation is %g * x + %d - %g * y + %d",
784 player
->scale_x
, player
->offset_x
, player
->scale_y
, player
->offset_y
);
786 /* FIXME: make this emit the signal at the right time */
787 player
->invalid
.x0
= 0;
788 player
->invalid
.y0
= 0;
789 player
->invalid
.x1
= player
->stage_width
;
790 player
->invalid
.y1
= player
->stage_height
;
795 swfdec_player_set_property (GObject
*object
, guint param_id
, const GValue
*value
,
798 SwfdecPlayer
*player
= SWFDEC_PLAYER (object
);
801 case PROP_BACKGROUND_COLOR
:
802 swfdec_player_set_background_color (player
, g_value_get_uint (value
));
804 case PROP_CACHE_SIZE
:
805 player
->cache
->max_size
= g_value_get_uint (value
);
808 swfdec_player_set_size (player
, g_value_get_int (value
), player
->stage_height
);
811 swfdec_player_set_size (player
, player
->stage_width
, g_value_get_int (value
));
814 player
->align_flags
= swfdec_player_alignment_to_flags (g_value_get_enum (value
));
815 swfdec_player_update_scale (player
);
818 swfdec_player_set_scale_mode (player
, g_value_get_enum (value
));
821 g_object_unref (player
->system
);
822 if (g_value_get_object (value
)) {
823 player
->system
= SWFDEC_SYSTEM (g_value_dup_object (value
));
825 player
->system
= swfdec_system_new ();
828 case PROP_MAX_RUNTIME
:
829 swfdec_player_set_maximum_runtime (player
, g_value_get_ulong (value
));
832 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, param_id
, pspec
);
838 swfdec_player_dispose (GObject
*object
)
840 SwfdecPlayer
*player
= SWFDEC_PLAYER (object
);
843 swfdec_player_stop_all_sounds (player
);
844 swfdec_player_resource_request_finish (player
);
845 g_hash_table_destroy (player
->registered_classes
);
847 while (player
->roots
)
848 swfdec_movie_destroy (player
->roots
->data
);
849 if (player
->resource
) {
850 g_object_unref (player
->resource
);
851 player
->resource
= NULL
;
854 /* we do this here so references to GC'd objects get freed */
855 G_OBJECT_CLASS (swfdec_player_parent_class
)->dispose (object
);
857 swfdec_player_remove_all_external_actions (player
, player
);
858 #ifndef G_DISABLE_ASSERT
860 SwfdecPlayerExternalAction
*action
;
861 while ((action
= swfdec_ring_buffer_pop (player
->external_actions
)) != NULL
) {
862 g_assert (action
->object
== NULL
); /* skip removed actions */
866 SwfdecPlayerAction
*action
;
867 for (i
= 0; i
< SWFDEC_PLAYER_N_ACTION_QUEUES
; i
++) {
868 while ((action
= swfdec_ring_buffer_pop (player
->actions
[i
])) != NULL
) {
869 g_assert (action
->movie
== NULL
); /* skip removed actions */
874 swfdec_ring_buffer_free (player
->external_actions
);
875 for (i
= 0; i
< SWFDEC_PLAYER_N_ACTION_QUEUES
; i
++) {
876 swfdec_ring_buffer_free (player
->actions
[i
]);
878 g_assert (player
->movies
== NULL
);
879 g_assert (player
->audio
== NULL
);
880 if (player
->external_timeout
.callback
)
881 swfdec_player_remove_timeout (player
, &player
->external_timeout
);
883 swfdec_player_remove_timeout (player
, &player
->iterate_timeout
);
885 g_assert (player
->timeouts
== NULL
);
886 g_list_free (player
->intervals
);
887 while (player
->rooted_objects
)
888 swfdec_player_unroot_object (player
, player
->rooted_objects
->data
);
889 player
->intervals
= NULL
;
890 swfdec_cache_unref (player
->cache
);
891 if (player
->system
) {
892 g_object_unref (player
->system
);
893 player
->system
= NULL
;
895 g_array_free (player
->invalidations
, TRUE
);
896 player
->invalidations
= NULL
;
897 if (player
->runtime
) {
898 g_timer_destroy (player
->runtime
);
899 player
->runtime
= NULL
;
904 swfdec_player_broadcast (SwfdecPlayer
*player
, const char *object_name
, const char *signal
)
909 SWFDEC_DEBUG ("broadcasting message %s.%s", object_name
, signal
);
910 obj
= SWFDEC_AS_CONTEXT (player
)->global
;
911 swfdec_as_object_get_variable (obj
, object_name
, &val
);
912 if (!SWFDEC_AS_VALUE_IS_OBJECT (&val
))
914 obj
= SWFDEC_AS_VALUE_GET_OBJECT (&val
);
915 SWFDEC_AS_VALUE_SET_STRING (&val
, signal
);
916 swfdec_as_object_call (obj
, SWFDEC_AS_STR_broadcastMessage
, 1, &val
, NULL
);
920 swfdec_player_update_mouse_cursor (SwfdecPlayer
*player
)
922 SwfdecMouseCursor
new = SWFDEC_MOUSE_CURSOR_NORMAL
;
924 if (!player
->mouse_visible
) {
925 new = SWFDEC_MOUSE_CURSOR_NONE
;
926 } else if (player
->mouse_grab
!= NULL
) {
927 /* FIXME: this needs to be more sophisticated, since SwfdecEditText may
928 * want to have different mouse cursors depending on location (it supports
931 if (SWFDEC_IS_BUTTON_MOVIE (player
->mouse_grab
))
932 new = SWFDEC_MOUSE_CURSOR_CLICK
;
935 if (new != player
->mouse_cursor
) {
936 player
->mouse_cursor
= new;
937 g_object_notify (G_OBJECT (player
), "mouse-cursor");
942 swfdec_player_update_drag_movie (SwfdecPlayer
*player
)
947 if (player
->mouse_drag
== NULL
)
950 movie
= player
->mouse_drag
;
951 g_assert (movie
->cache_state
== SWFDEC_MOVIE_UP_TO_DATE
);
954 swfdec_player_stage_to_global (player
, &x
, &y
);
956 swfdec_movie_global_to_local (movie
->parent
, &x
, &y
);
957 if (player
->mouse_drag_center
) {
958 x
-= (movie
->extents
.x1
- movie
->extents
.x0
) / 2;
959 y
-= (movie
->extents
.y1
- movie
->extents
.y0
) / 2;
961 x
-= player
->mouse_drag_x
;
962 y
-= player
->mouse_drag_y
;
964 x
= CLAMP (x
, player
->mouse_drag_rect
.x0
, player
->mouse_drag_rect
.x1
);
965 y
= CLAMP (y
, player
->mouse_drag_rect
.y0
, player
->mouse_drag_rect
.y1
);
966 SWFDEC_LOG ("mouse is at %g %g, originally (%g %g)", x
, y
, player
->mouse_x
, player
->mouse_y
);
967 if (x
!= movie
->matrix
.x0
|| y
!= movie
->matrix
.y0
) {
968 movie
->matrix
.x0
= x
;
969 movie
->matrix
.y0
= y
;
970 swfdec_movie_queue_update (movie
, SWFDEC_MOVIE_INVALID_MATRIX
);
975 * swfdec_player_set_drag_movie:
976 * @player: a #SwfdecPlayer
977 * @drag: the movie to be dragged by the mouse or NULL to unset
978 * @center: TRUE if the center of @drag should be at the mouse pointer, FALSE if (0,0)
979 * of @drag should be at the mouse pointer.
980 * @rect: NULL or the rectangle that clips the mouse position. The coordinates
981 * are in the coordinate system of the parent of @drag.
983 * Sets or unsets the movie that is dragged by the mouse.
986 swfdec_player_set_drag_movie (SwfdecPlayer
*player
, SwfdecMovie
*drag
, gboolean center
,
989 g_return_if_fail (SWFDEC_IS_PLAYER (player
));
990 g_return_if_fail (drag
== NULL
|| SWFDEC_IS_MOVIE (drag
));
992 /* FIXME: need to do anything with old drag? */
993 player
->mouse_drag
= drag
;
994 player
->mouse_drag_center
= center
;
995 if (drag
&& !center
) {
996 player
->mouse_drag_x
= player
->mouse_x
;
997 player
->mouse_drag_y
= player
->mouse_y
;
998 swfdec_player_stage_to_global (player
, &player
->mouse_drag_x
, &player
->mouse_drag_y
);
1000 swfdec_movie_global_to_local (drag
->parent
, &player
->mouse_drag_x
, &player
->mouse_drag_y
);
1001 player
->mouse_drag_x
-= drag
->matrix
.x0
;
1002 player
->mouse_drag_y
-= drag
->matrix
.y0
;
1005 player
->mouse_drag_rect
= *rect
;
1007 player
->mouse_drag_rect
.x0
= -G_MAXDOUBLE
;
1008 player
->mouse_drag_rect
.y0
= -G_MAXDOUBLE
;
1009 player
->mouse_drag_rect
.x1
= G_MAXDOUBLE
;
1010 player
->mouse_drag_rect
.y1
= G_MAXDOUBLE
;
1012 SWFDEC_DEBUG ("starting drag in %g %g %g %g",
1013 player
->mouse_drag_rect
.x0
, player
->mouse_drag_rect
.y0
,
1014 player
->mouse_drag_rect
.x1
, player
->mouse_drag_rect
.y1
);
1015 /* FIXME: need a way to make sure we get updated */
1017 swfdec_movie_update (drag
);
1018 drag
->modified
= TRUE
;
1019 swfdec_player_update_drag_movie (player
);
1024 swfdec_player_update_mouse_position (SwfdecPlayer
*player
)
1027 SwfdecMovie
*mouse_grab
= NULL
;
1029 if (player
->mouse_button
) {
1030 mouse_grab
= player
->mouse_grab
;
1033 /* if the mouse button is pressed the grab widget stays the same (I think) */
1034 x
= player
->mouse_x
;
1035 y
= player
->mouse_y
;
1036 swfdec_player_stage_to_global (player
, &x
, &y
);
1037 for (walk
= g_list_last (player
->roots
); walk
; walk
= walk
->prev
) {
1038 mouse_grab
= swfdec_movie_get_movie_at (walk
->data
, x
, y
);
1043 SWFDEC_DEBUG ("%s %p has mouse at %g %g",
1044 mouse_grab
? G_OBJECT_TYPE_NAME (mouse_grab
) : "---",
1045 mouse_grab
, player
->mouse_x
, player
->mouse_y
);
1046 if (player
->mouse_grab
&& mouse_grab
!= player
->mouse_grab
)
1047 swfdec_movie_send_mouse_change (player
->mouse_grab
, TRUE
);
1048 player
->mouse_grab
= mouse_grab
;
1050 swfdec_movie_send_mouse_change (mouse_grab
, FALSE
);
1054 swfdec_player_do_mouse_move (SwfdecPlayer
*player
)
1058 swfdec_player_update_drag_movie (player
);
1059 for (walk
= player
->movies
; walk
; walk
= walk
->next
) {
1060 swfdec_movie_queue_script (walk
->data
, SWFDEC_EVENT_MOUSE_MOVE
);
1062 swfdec_player_broadcast (player
, SWFDEC_AS_STR_Mouse
, SWFDEC_AS_STR_onMouseMove
);
1063 swfdec_player_update_mouse_position (player
);
1067 swfdec_player_do_mouse_button (SwfdecPlayer
*player
)
1071 const char *event_name
;
1073 if (player
->mouse_button
) {
1074 event
= SWFDEC_EVENT_MOUSE_DOWN
;
1075 event_name
= SWFDEC_AS_STR_onMouseDown
;
1077 event
= SWFDEC_EVENT_MOUSE_UP
;
1078 event_name
= SWFDEC_AS_STR_onMouseUp
;
1080 for (walk
= player
->movies
; walk
; walk
= walk
->next
) {
1081 swfdec_movie_queue_script (walk
->data
, event
);
1083 swfdec_player_broadcast (player
, SWFDEC_AS_STR_Mouse
, event_name
);
1084 if (player
->mouse_grab
)
1085 swfdec_movie_send_mouse_change (player
->mouse_grab
, FALSE
);
1089 swfdec_player_emit_signals (SwfdecPlayer
*player
)
1093 /* emit invalidate signal */
1094 if (!swfdec_rectangle_is_empty (&player
->invalid_extents
)) {
1095 g_signal_emit (player
, signals
[INVALIDATE
], 0, &player
->invalid_extents
,
1096 player
->invalidations
->data
, player
->invalidations
->len
);
1097 swfdec_rectangle_init_empty (&player
->invalid_extents
);
1098 g_array_set_size (player
->invalidations
, 0);
1101 /* emit audio-added for all added audio streams */
1102 for (walk
= player
->audio
; walk
; walk
= walk
->next
) {
1103 SwfdecAudio
*audio
= walk
->data
;
1107 g_signal_emit (player
, signals
[AUDIO_ADDED
], 0, audio
);
1108 audio
->added
= TRUE
;
1113 swfdec_player_do_handle_key (SwfdecPlayer
*player
, guint keycode
, guint character
, gboolean down
)
1115 g_assert (keycode
< 256);
1117 if (!swfdec_player_lock (player
))
1119 /* set the correct variables */
1120 player
->last_keycode
= keycode
;
1121 player
->last_character
= character
;
1123 player
->key_pressed
[keycode
/ 8] |= 1 << keycode
% 8;
1125 player
->key_pressed
[keycode
/ 8] &= ~(1 << keycode
% 8);
1127 swfdec_player_broadcast (player
, SWFDEC_AS_STR_Key
, down
? SWFDEC_AS_STR_onKeyDown
: SWFDEC_AS_STR_onKeyUp
);
1128 swfdec_player_perform_actions (player
);
1129 swfdec_player_unlock (player
);
1135 swfdec_player_do_handle_mouse (SwfdecPlayer
*player
,
1136 double x
, double y
, int button
)
1138 if (!swfdec_player_lock (player
))
1141 SWFDEC_LOG ("handling mouse at %g %g %d", x
, y
, button
);
1142 if (player
->mouse_x
!= x
|| player
->mouse_y
!= y
) {
1143 player
->mouse_x
= x
;
1144 player
->mouse_y
= y
;
1145 swfdec_player_do_mouse_move (player
);
1147 if (player
->mouse_button
!= button
) {
1148 player
->mouse_button
= button
;
1149 swfdec_player_do_mouse_button (player
);
1151 swfdec_player_perform_actions (player
);
1152 swfdec_player_unlock (player
);
1154 /* FIXME: allow events to pass through */
1159 swfdec_player_global_to_stage (SwfdecPlayer
*player
, double *x
, double *y
)
1161 g_return_if_fail (SWFDEC_IS_PLAYER (player
));
1162 g_return_if_fail (x
!= NULL
);
1163 g_return_if_fail (y
!= NULL
);
1165 *x
= *x
/ SWFDEC_TWIPS_SCALE_FACTOR
* player
->scale_x
+ player
->offset_x
;
1166 *y
= *y
/ SWFDEC_TWIPS_SCALE_FACTOR
* player
->scale_y
+ player
->offset_y
;
1170 swfdec_player_stage_to_global (SwfdecPlayer
*player
, double *x
, double *y
)
1172 g_return_if_fail (SWFDEC_IS_PLAYER (player
));
1173 g_return_if_fail (x
!= NULL
);
1174 g_return_if_fail (y
!= NULL
);
1176 *x
= (*x
- player
->offset_x
) / player
->scale_x
* SWFDEC_TWIPS_SCALE_FACTOR
;
1177 *y
= (*y
- player
->offset_y
) / player
->scale_y
* SWFDEC_TWIPS_SCALE_FACTOR
;
1181 swfdec_player_execute_on_load_init (SwfdecPlayer
*player
)
1185 /* FIXME: This can be made a LOT faster with correct caching, but I'm lazy */
1187 for (walk
= player
->movies
; walk
; walk
= walk
->next
) {
1188 SwfdecMovie
*movie
= walk
->data
;
1189 SwfdecResource
*resource
= swfdec_movie_get_own_resource (movie
);
1190 if (resource
== NULL
)
1192 if (swfdec_resource_emit_on_load_init (resource
))
1195 } while (walk
!= NULL
);
1199 swfdec_player_iterate (SwfdecTimeout
*timeout
)
1201 SwfdecPlayer
*player
= SWFDEC_PLAYER ((guint8
*) timeout
- G_STRUCT_OFFSET (SwfdecPlayer
, iterate_timeout
));
1204 /* add timeout again - do this first because later code can change it */
1205 /* FIXME: rounding issues? */
1206 player
->iterate_timeout
.timestamp
+= SWFDEC_TICKS_PER_SECOND
* 256 / player
->rate
;
1207 swfdec_player_add_timeout (player
, &player
->iterate_timeout
);
1208 swfdec_player_perform_external_actions (player
);
1209 SWFDEC_INFO ("=== START ITERATION ===");
1210 /* start the iteration. This performs a goto next frame on all
1211 * movies that are not stopped. It also queues onEnterFrame.
1213 for (walk
= player
->movies
; walk
; walk
= walk
->next
) {
1214 SwfdecMovieClass
*klass
= SWFDEC_MOVIE_GET_CLASS (walk
->data
);
1215 if (klass
->iterate_start
)
1216 klass
->iterate_start (walk
->data
);
1218 swfdec_player_perform_actions (player
);
1219 SWFDEC_INFO ("=== STOP ITERATION ===");
1220 /* this loop allows removal of walk->data */
1221 walk
= player
->movies
;
1223 SwfdecMovie
*cur
= walk
->data
;
1224 SwfdecMovieClass
*klass
= SWFDEC_MOVIE_GET_CLASS (cur
);
1226 g_assert (klass
->iterate_end
);
1227 if (!klass
->iterate_end (cur
))
1228 swfdec_movie_destroy (cur
);
1230 swfdec_player_execute_on_load_init (player
);
1231 swfdec_player_resource_request_perform (player
);
1232 swfdec_player_perform_actions (player
);
1236 swfdec_player_advance_audio (SwfdecPlayer
*player
, guint samples
)
1244 /* don't use for loop here, because we need to advance walk before
1245 * removing the audio */
1246 walk
= player
->audio
;
1250 if (swfdec_audio_iterate (audio
, samples
) == 0)
1251 swfdec_audio_remove (audio
);
1256 swfdec_player_do_advance (SwfdecPlayer
*player
, gulong msecs
, guint audio_samples
)
1258 SwfdecTimeout
*timeout
;
1259 SwfdecTick target_time
;
1262 if (!swfdec_player_lock (player
))
1265 target_time
= player
->time
+ SWFDEC_MSECS_TO_TICKS (msecs
);
1266 SWFDEC_DEBUG ("advancing %lu msecs (%u audio frames)", msecs
, audio_samples
);
1268 for (timeout
= player
->timeouts
? player
->timeouts
->data
: NULL
;
1269 timeout
&& timeout
->timestamp
<= target_time
;
1270 timeout
= player
->timeouts
? player
->timeouts
->data
: NULL
) {
1271 player
->timeouts
= g_list_remove (player
->timeouts
, timeout
);
1272 frames_now
= SWFDEC_TICKS_TO_SAMPLES (timeout
->timestamp
) -
1273 SWFDEC_TICKS_TO_SAMPLES (player
->time
);
1274 player
->time
= timeout
->timestamp
;
1275 swfdec_player_advance_audio (player
, frames_now
);
1276 audio_samples
-= frames_now
;
1277 SWFDEC_LOG ("activating timeout %p now (timeout is %"G_GUINT64_FORMAT
", target time is %"G_GUINT64_FORMAT
,
1278 timeout
, timeout
->timestamp
, target_time
);
1279 timeout
->callback (timeout
);
1280 swfdec_player_perform_actions (player
);
1282 if (target_time
> player
->time
) {
1283 frames_now
= SWFDEC_TICKS_TO_SAMPLES (target_time
) -
1284 SWFDEC_TICKS_TO_SAMPLES (player
->time
);
1285 player
->time
= target_time
;
1286 swfdec_player_advance_audio (player
, frames_now
);
1287 audio_samples
-= frames_now
;
1289 g_assert (audio_samples
== 0);
1291 swfdec_player_unlock (player
);
1295 swfdec_player_perform_actions (SwfdecPlayer
*player
)
1299 g_return_if_fail (SWFDEC_IS_PLAYER (player
));
1301 while (swfdec_player_do_action (player
));
1302 for (walk
= player
->roots
; walk
; walk
= walk
->next
) {
1303 swfdec_movie_update (walk
->data
);
1305 /* update the state of the mouse when stuff below it moved */
1306 if (swfdec_rectangle_contains_point (&player
->invalid_extents
, player
->mouse_x
, player
->mouse_y
)) {
1307 SWFDEC_INFO ("=== NEED TO UPDATE mouse post-iteration ===");
1308 swfdec_player_update_mouse_position (player
);
1309 while (swfdec_player_do_action (player
));
1310 for (walk
= player
->roots
; walk
; walk
= walk
->next
) {
1311 swfdec_movie_update (walk
->data
);
1316 /* used for breakpoints */
1318 swfdec_player_lock_soft (SwfdecPlayer
*player
)
1320 g_return_if_fail (SWFDEC_IS_PLAYER (player
));
1321 g_assert (swfdec_rectangle_is_empty (&player
->invalid_extents
));
1323 g_object_freeze_notify (G_OBJECT (player
));
1324 g_timer_start (player
->runtime
);
1325 SWFDEC_DEBUG ("LOCKED");
1329 swfdec_player_lock (SwfdecPlayer
*player
)
1331 g_return_val_if_fail (SWFDEC_IS_PLAYER (player
), FALSE
);
1332 g_assert (swfdec_ring_buffer_get_n_elements (player
->actions
[0]) == 0);
1333 g_assert (swfdec_ring_buffer_get_n_elements (player
->actions
[1]) == 0);
1334 g_assert (swfdec_ring_buffer_get_n_elements (player
->actions
[2]) == 0);
1335 g_assert (swfdec_ring_buffer_get_n_elements (player
->actions
[3]) == 0);
1337 if (swfdec_as_context_is_aborted (SWFDEC_AS_CONTEXT (player
)))
1340 g_object_ref (player
);
1341 swfdec_player_lock_soft (player
);
1345 /* used for breakpoints */
1347 swfdec_player_unlock_soft (SwfdecPlayer
*player
)
1349 g_return_if_fail (SWFDEC_IS_PLAYER (player
));
1351 SWFDEC_DEBUG ("UNLOCK");
1352 g_timer_stop (player
->runtime
);
1353 swfdec_player_update_mouse_cursor (player
);
1354 g_object_thaw_notify (G_OBJECT (player
));
1355 swfdec_player_emit_signals (player
);
1359 swfdec_player_unlock (SwfdecPlayer
*player
)
1361 SwfdecAsContext
*context
;
1363 g_return_if_fail (SWFDEC_IS_PLAYER (player
));
1364 g_assert (swfdec_ring_buffer_get_n_elements (player
->actions
[0]) == 0);
1365 g_assert (swfdec_ring_buffer_get_n_elements (player
->actions
[1]) == 0);
1366 g_assert (swfdec_ring_buffer_get_n_elements (player
->actions
[2]) == 0);
1367 g_assert (swfdec_ring_buffer_get_n_elements (player
->actions
[3]) == 0);
1368 context
= SWFDEC_AS_CONTEXT (player
);
1369 g_return_if_fail (context
->state
!= SWFDEC_AS_CONTEXT_INTERRUPTED
);
1371 if (context
->state
== SWFDEC_AS_CONTEXT_RUNNING
)
1372 swfdec_as_context_maybe_gc (SWFDEC_AS_CONTEXT (player
));
1373 swfdec_player_unlock_soft (player
);
1374 g_object_unref (player
);
1378 swfdec_accumulate_or (GSignalInvocationHint
*ihint
, GValue
*return_accu
,
1379 const GValue
*handler_return
, gpointer data
)
1381 if (g_value_get_boolean (handler_return
))
1382 g_value_set_boolean (return_accu
, TRUE
);
1387 swfdec_player_mark_string_object (gpointer key
, gpointer value
, gpointer data
)
1389 swfdec_as_string_mark (key
);
1390 swfdec_as_object_mark (value
);
1394 swfdec_player_mark_rooted_object (gpointer object
, gpointer unused
)
1396 if (SWFDEC_IS_RESOURCE (object
)) {
1397 swfdec_resource_mark (object
);
1398 } else if (SWFDEC_IS_AS_OBJECT (object
)) {
1399 swfdec_as_object_mark (object
);
1404 swfdec_player_mark (SwfdecAsContext
*context
)
1406 SwfdecPlayer
*player
= SWFDEC_PLAYER (context
);
1408 g_hash_table_foreach (player
->registered_classes
, swfdec_player_mark_string_object
, NULL
);
1409 swfdec_as_object_mark (player
->MovieClip
);
1410 swfdec_as_object_mark (player
->Video
);
1411 g_list_foreach (player
->roots
, (GFunc
) swfdec_as_object_mark
, NULL
);
1412 g_list_foreach (player
->intervals
, (GFunc
) swfdec_as_object_mark
, NULL
);
1413 g_list_foreach (player
->rooted_objects
, swfdec_player_mark_rooted_object
, NULL
);
1415 SWFDEC_AS_CONTEXT_CLASS (swfdec_player_parent_class
)->mark (context
);
1419 swfdec_player_get_time (SwfdecAsContext
*context
, GTimeVal
*tv
)
1421 *tv
= context
->start_time
;
1423 /* FIXME: what granularity do we want? Currently it's milliseconds */
1424 g_time_val_add (tv
, SWFDEC_TICKS_TO_MSECS (SWFDEC_PLAYER (context
)->time
) * 1000);
1428 swfdec_player_check_continue (SwfdecAsContext
*context
)
1430 SwfdecPlayer
*player
= SWFDEC_PLAYER (context
);
1432 if (player
->max_runtime
== 0)
1434 return g_timer_elapsed (player
->runtime
, NULL
) * 1000 <= player
->max_runtime
;
1438 swfdec_player_class_init (SwfdecPlayerClass
*klass
)
1440 GObjectClass
*object_class
= G_OBJECT_CLASS (klass
);
1441 SwfdecAsContextClass
*context_class
= SWFDEC_AS_CONTEXT_CLASS (klass
);
1443 object_class
->get_property
= swfdec_player_get_property
;
1444 object_class
->set_property
= swfdec_player_set_property
;
1445 object_class
->dispose
= swfdec_player_dispose
;
1447 g_object_class_install_property (object_class
, PROP_INITIALIZED
,
1448 g_param_spec_boolean ("initialized", "initialized", "TRUE when the player has initialized its basic values",
1449 FALSE
, G_PARAM_READABLE
));
1450 g_object_class_install_property (object_class
, PROP_DEFAULT_WIDTH
,
1451 g_param_spec_uint ("default-width", "default width", "default width of the movie",
1452 0, G_MAXUINT
, 0, G_PARAM_READABLE
));
1453 g_object_class_install_property (object_class
, PROP_DEFAULT_HEIGHT
,
1454 g_param_spec_uint ("default-height", "default height", "default height of the movie",
1455 0, G_MAXUINT
, 0, G_PARAM_READABLE
));
1456 g_object_class_install_property (object_class
, PROP_RATE
,
1457 g_param_spec_double ("rate", "rate", "rate in frames per second",
1458 0.0, 256.0, 0.0, G_PARAM_READABLE
));
1459 g_object_class_install_property (object_class
, PROP_MOUSE_CURSOR
,
1460 g_param_spec_enum ("mouse-cursor", "mouse cursor", "how the mouse pointer should be presented",
1461 SWFDEC_TYPE_MOUSE_CURSOR
, SWFDEC_MOUSE_CURSOR_NONE
, G_PARAM_READABLE
));
1462 g_object_class_install_property (object_class
, PROP_NEXT_EVENT
,
1463 g_param_spec_long ("next-event", "next event", "how many milliseconds until the next event or 0 when no event pending",
1464 -1, G_MAXLONG
, -1, G_PARAM_READABLE
));
1465 g_object_class_install_property (object_class
, PROP_CACHE_SIZE
,
1466 g_param_spec_uint ("cache-size", "cache size", "maximum cache size in bytes",
1467 0, G_MAXUINT
, 50 * 1024 * 1024, G_PARAM_READABLE
));
1468 g_object_class_install_property (object_class
, PROP_BACKGROUND_COLOR
,
1469 g_param_spec_uint ("background-color", "background color", "ARGB color used to draw the background",
1470 0, G_MAXUINT
, SWFDEC_COLOR_COMBINE (0xFF, 0xFF, 0xFF, 0xFF), G_PARAM_READWRITE
));
1471 g_object_class_install_property (object_class
, PROP_WIDTH
,
1472 g_param_spec_int ("width", "width", "current width of the movie",
1473 -1, G_MAXINT
, -1, G_PARAM_READWRITE
));
1474 g_object_class_install_property (object_class
, PROP_HEIGHT
,
1475 g_param_spec_int ("height", "height", "current height of the movie",
1476 -1, G_MAXINT
, -1, G_PARAM_READWRITE
));
1477 g_object_class_install_property (object_class
, PROP_ALIGNMENT
,
1478 g_param_spec_enum ("alignment", "alignment", "point of the screen to align the output to",
1479 SWFDEC_TYPE_ALIGNMENT
, SWFDEC_ALIGNMENT_CENTER
, G_PARAM_READWRITE
));
1480 g_object_class_install_property (object_class
, PROP_SCALE
,
1481 g_param_spec_enum ("scale-mode", "scale mode", "method used to scale the movie",
1482 SWFDEC_TYPE_SCALE_MODE
, SWFDEC_SCALE_SHOW_ALL
, G_PARAM_READWRITE
));
1483 g_object_class_install_property (object_class
, PROP_SCALE
,
1484 g_param_spec_object ("system", "system", "object holding system information",
1485 SWFDEC_TYPE_SYSTEM
, G_PARAM_READWRITE
));
1486 g_object_class_install_property (object_class
, PROP_MAX_RUNTIME
,
1487 g_param_spec_ulong ("max-runtime", "maximum runtime", "maximum time in msecs scripts may run in the player before aborting",
1488 0, G_MAXULONG
, 10 * 1000, G_PARAM_READWRITE
));
1491 * SwfdecPlayer::invalidate:
1492 * @player: the #SwfdecPlayer affected
1493 * @extents: the smallest rectangle enclosing the full region of changes
1494 * @rectangles: a number of smaller rectangles for fine-grained control over
1496 * @n_rectangles: number of rectangles in @rectangles
1498 * This signal is emitted whenever graphical elements inside the player have
1499 * changed. It provides two ways to look at the changes: By looking at the
1500 * @extents parameter, it provides a simple way to get a single rectangle that
1501 * encloses all changes. By looking at the @rectangles array, you can get
1502 * finer control over changes which is very useful if your rendering system
1503 * provides a way to handle regions.
1505 signals
[INVALIDATE
] = g_signal_new ("invalidate", G_TYPE_FROM_CLASS (klass
),
1506 G_SIGNAL_RUN_LAST
, 0, NULL
, NULL
, swfdec_marshal_VOID__BOXED_POINTER_UINT
,
1507 G_TYPE_NONE
, 3, SWFDEC_TYPE_RECTANGLE
, G_TYPE_POINTER
, G_TYPE_UINT
);
1509 * SwfdecPlayer::advance:
1510 * @player: the #SwfdecPlayer affected
1511 * @msecs: the amount of milliseconds the player will advance
1512 * @audio_samples: number of frames the audio is advanced (in 44100Hz steps)
1514 * Emitted whenever the player advances.
1516 signals
[ADVANCE
] = g_signal_new ("advance", G_TYPE_FROM_CLASS (klass
),
1517 G_SIGNAL_RUN_LAST
, G_STRUCT_OFFSET (SwfdecPlayerClass
, advance
),
1518 NULL
, NULL
, swfdec_marshal_VOID__ULONG_UINT
,
1519 G_TYPE_NONE
, 2, G_TYPE_ULONG
, G_TYPE_UINT
);
1521 * SwfdecPlayer::handle-key:
1522 * @player: the #SwfdecPlayer affected
1523 * @key: #SwfdecKey that was pressed or released
1524 * @pressed: %TRUE if the @key was pressed or %FALSE if it was released
1526 * This signal is emitted whenever @player should respond to a key event. If
1527 * any of the handlers returns TRUE, swfdec_player_key_press() or
1528 * swfdec_player_key_release() will return TRUE. Note that unlike many event
1529 * handlers in gtk, returning TRUE will not stop further event handlers from
1530 * being invoked. Use g_signal_stop_emission() in that case.
1532 * Returns: TRUE if this handler handles the event.
1534 signals
[HANDLE_KEY
] = g_signal_new ("handle-key", G_TYPE_FROM_CLASS (klass
),
1535 G_SIGNAL_RUN_LAST
, G_STRUCT_OFFSET (SwfdecPlayerClass
, handle_key
),
1536 swfdec_accumulate_or
, NULL
, swfdec_marshal_BOOLEAN__UINT_UINT_BOOLEAN
,
1537 G_TYPE_BOOLEAN
, 3, G_TYPE_UINT
, G_TYPE_UINT
, G_TYPE_BOOLEAN
);
1539 * SwfdecPlayer::handle-mouse:
1540 * @player: the #SwfdecPlayer affected
1541 * @x: new x coordinate of the mouse
1542 * @y: new y coordinate of the mouse
1543 * @button: 1 if the button is pressed, 0 if not
1545 * This signal is emitted whenever @player should respond to a mouse event. If
1546 * any of the handlers returns TRUE, swfdec_player_handle_mouse() will return
1547 * TRUE. Note that unlike many event handlers in gtk, returning TRUE will not
1548 * stop further event handlers from being invoked. Use g_signal_stop_emission()
1551 * Returns: TRUE if this handler handles the event.
1553 signals
[HANDLE_MOUSE
] = g_signal_new ("handle-mouse", G_TYPE_FROM_CLASS (klass
),
1554 G_SIGNAL_RUN_LAST
, G_STRUCT_OFFSET (SwfdecPlayerClass
, handle_mouse
),
1555 swfdec_accumulate_or
, NULL
, swfdec_marshal_BOOLEAN__DOUBLE_DOUBLE_INT
,
1556 G_TYPE_BOOLEAN
, 3, G_TYPE_DOUBLE
, G_TYPE_DOUBLE
, G_TYPE_INT
);
1558 * SwfdecPlayer::audio-added:
1559 * @player: the #SwfdecPlayer affected
1560 * @audio: the audio stream that was added
1562 * Emitted whenever a new audio stream was added to @player.
1564 signals
[AUDIO_ADDED
] = g_signal_new ("audio-added", G_TYPE_FROM_CLASS (klass
),
1565 G_SIGNAL_RUN_LAST
, 0, NULL
, NULL
, g_cclosure_marshal_VOID__OBJECT
,
1566 G_TYPE_NONE
, 1, SWFDEC_TYPE_AUDIO
);
1568 * SwfdecPlayer::audio-removed:
1569 * @player: the #SwfdecPlayer affected
1570 * @audio: the audio stream that was removed
1572 * Emitted whenever an audio stream was removed from @player. The stream will
1573 * have been added with the SwfdecPlayer::audio-added signal previously.
1575 signals
[AUDIO_REMOVED
] = g_signal_new ("audio-removed", G_TYPE_FROM_CLASS (klass
),
1576 G_SIGNAL_RUN_LAST
, 0, NULL
, NULL
, g_cclosure_marshal_VOID__OBJECT
,
1577 G_TYPE_NONE
, 1, SWFDEC_TYPE_AUDIO
);
1579 * SwfdecPlayer::fscommand:
1580 * @player: the #SwfdecPlayer affected
1581 * @command: the command to execute. This is a lower case string.
1582 * @parameter: parameter to pass to the command. The parameter depends on the
1585 * This signal is emited whenever a Flash script command (also known as
1586 * fscommand) is encountered. This method is ued by the Flash file to
1587 * communicate with the hosting environment. In web browsers it is used to
1588 * call Javascript functions. Standalone Flash players understand a limited
1589 * set of functions. They vary from player to player, but the most common are
1590 * listed here: <itemizedlist>
1591 * <listitem><para>"quit": quits the player.</para></listitem>
1592 * <listitem><para>"fullscreen": A boolean setting (parameter is "true" or
1593 * "false") that sets the player into fullscreen mode.</para></listitem>
1594 * <listitem><para>"allowscale": A boolean setting that tells the player to
1595 * not scale the Flash application.</para></listitem>
1596 * <listitem><para>"showmenu": A boolean setting that tells the Flash player
1597 * to not show its own entries in the right-click menu.</para></listitem>
1598 * <listitem><para>"exec": Run an external executable. The parameter
1599 * specifies the path.</para></listitem>
1600 * <listitem><para>"trapallkeys": A boolean setting that tells the Flash
1601 * player to pass all key events to the Flash application instead of using it
1602 * for keyboard shortcuts or similar.</para></listitem>
1605 signals
[FSCOMMAND
] = g_signal_new ("fscommand", G_TYPE_FROM_CLASS (klass
),
1606 G_SIGNAL_RUN_LAST
, 0, NULL
, NULL
, swfdec_marshal_VOID__STRING_STRING
,
1607 G_TYPE_NONE
, 2, G_TYPE_STRING
, G_TYPE_STRING
);
1609 * SwfdecPlayer::launch:
1610 * @player: the #SwfdecPlayer affected
1611 * @request: the type of request
1613 * @target: target to load the URL into
1614 * @data: optional data to pass on with the request. Will be of mime type
1615 * application/x-www-form-urlencoded. Can be %NULL indicating no data
1618 * Emitted whenever the @player encounters an URL that should be loaded into
1619 * a target the Flash player does not recognize. In most cases this happens
1620 * when the user clicks a link in an embedded Flash movie that should open a
1622 * The effect of calling any swfdec functions on the emitting @player is undefined.
1624 signals
[LAUNCH
] = g_signal_new ("launch", G_TYPE_FROM_CLASS (klass
),
1625 G_SIGNAL_RUN_LAST
, 0, NULL
, NULL
, swfdec_marshal_VOID__ENUM_STRING_STRING_BOXED
,
1626 G_TYPE_NONE
, 4, SWFDEC_TYPE_LOADER_REQUEST
, G_TYPE_STRING
, G_TYPE_STRING
,
1627 SWFDEC_TYPE_BUFFER
);
1629 context_class
->mark
= swfdec_player_mark
;
1630 context_class
->get_time
= swfdec_player_get_time
;
1631 context_class
->check_continue
= swfdec_player_check_continue
;
1633 klass
->advance
= swfdec_player_do_advance
;
1634 klass
->handle_key
= swfdec_player_do_handle_key
;
1635 klass
->handle_mouse
= swfdec_player_do_handle_mouse
;
1639 swfdec_player_init (SwfdecPlayer
*player
)
1643 player
->system
= swfdec_system_new ();
1644 player
->registered_classes
= g_hash_table_new (g_direct_hash
, g_direct_equal
);
1646 for (i
= 0; i
< SWFDEC_PLAYER_N_ACTION_QUEUES
; i
++) {
1647 player
->actions
[i
] = swfdec_ring_buffer_new_for_type (SwfdecPlayerAction
, 16);
1649 player
->external_actions
= swfdec_ring_buffer_new_for_type (SwfdecPlayerExternalAction
, 8);
1650 player
->cache
= swfdec_cache_new (50 * 1024 * 1024); /* 100 MB */
1651 player
->bgcolor
= SWFDEC_COLOR_COMBINE (0xFF, 0xFF, 0xFF, 0xFF);
1653 player
->runtime
= g_timer_new ();
1654 g_timer_stop (player
->runtime
);
1655 player
->max_runtime
= 10 * 1000;
1656 player
->invalidations
= g_array_new (FALSE
, FALSE
, sizeof (SwfdecRectangle
));
1657 player
->mouse_visible
= TRUE
;
1658 player
->mouse_cursor
= SWFDEC_MOUSE_CURSOR_NORMAL
;
1659 player
->iterate_timeout
.callback
= swfdec_player_iterate
;
1660 player
->stage_width
= -1;
1661 player
->stage_height
= -1;
1663 swfdec_player_resource_request_init (player
);
1667 swfdec_player_stop_all_sounds (SwfdecPlayer
*player
)
1669 g_return_if_fail (SWFDEC_IS_PLAYER (player
));
1671 while (player
->audio
) {
1672 swfdec_audio_remove (player
->audio
->data
);
1677 swfdec_player_stop_sounds (SwfdecPlayer
*player
, SwfdecAudioRemoveFunc func
, gpointer data
)
1681 g_return_if_fail (SWFDEC_IS_PLAYER (player
));
1682 g_return_if_fail (func
);
1684 walk
= player
->audio
;
1686 SwfdecAudio
*audio
= walk
->data
;
1688 if (func (audio
, data
))
1689 swfdec_audio_remove (audio
);
1693 /* rect is in global coordinates */
1695 swfdec_player_invalidate (SwfdecPlayer
*player
, const SwfdecRect
*rect
)
1701 if (swfdec_rect_is_empty (rect
)) {
1702 SWFDEC_ERROR ("called with an empty rectanle. In theory this shouldn't happen.");
1703 SWFDEC_ERROR (" However, degenerate matrixes can cause this. We need a fix for that.");
1708 swfdec_player_global_to_stage (player
, &tmp
.x0
, &tmp
.y0
);
1709 swfdec_player_global_to_stage (player
, &tmp
.x1
, &tmp
.y1
);
1710 swfdec_rectangle_init_rect (&r
, &tmp
);
1711 /* FIXME: currently we clamp the rectangle to the visible area, it might
1712 * be useful to allow out-of-bounds drawing. In that case this needs to be
1714 swfdec_rectangle_intersect (&r
, &r
, &player
->stage
);
1715 if (swfdec_rectangle_is_empty (&r
))
1718 /* FIXME: get region code into swfdec? */
1719 for (i
= 0; i
< player
->invalidations
->len
; i
++) {
1720 SwfdecRectangle
*cur
= &g_array_index (player
->invalidations
, SwfdecRectangle
, i
);
1721 if (swfdec_rectangle_contains (cur
, &r
))
1723 if (swfdec_rectangle_contains (&r
, cur
)) {
1725 swfdec_rectangle_union (&player
->invalid_extents
, &player
->invalid_extents
, &r
);
1728 if (i
== player
->invalidations
->len
) {
1729 g_array_append_val (player
->invalidations
, r
);
1730 swfdec_rectangle_union (&player
->invalid_extents
, &player
->invalid_extents
, &r
);
1732 SWFDEC_DEBUG ("toplevel invalidation of %g %g %g %g - invalid region now %d %d %d %d (%u subregions)",
1733 rect
->x0
, rect
->y0
, rect
->x1
, rect
->y1
,
1734 player
->invalid_extents
.x
, player
->invalid_extents
.y
,
1735 player
->invalid_extents
.x
+ player
->invalid_extents
.width
,
1736 player
->invalid_extents
.y
+ player
->invalid_extents
.height
,
1737 player
->invalidations
->len
);
1741 * swfdec_player_get_level:
1742 * @player: a #SwfdecPlayer
1743 * @name: a name that is supposed to refer to a level
1745 * Checks if the given @name refers to a level, and if so, returns the level.
1746 * An example for such a name is "_level5". These strings are used to refer to
1747 * root movies inside the Flash player.
1749 * Returns: the level referred to by @name or -1 if none
1752 swfdec_player_get_level (SwfdecPlayer
*player
, const char *name
)
1757 g_return_val_if_fail (SWFDEC_IS_PLAYER (player
), -1);
1758 g_return_val_if_fail (name
!= NULL
, -1);
1760 /* check name starts with "_level" */
1761 if (swfdec_strncmp (SWFDEC_AS_CONTEXT (player
)->version
, name
, "_level", 6) != 0)
1764 /* extract depth from rest string (or fail if it's not a depth) */
1766 l
= strtoul (name
, &end
, 10);
1767 if (errno
!= 0 || *end
!= 0 || l
> G_MAXINT
)
1773 swfdec_player_create_movie_at_level (SwfdecPlayer
*player
, SwfdecResource
*resource
,
1779 g_return_val_if_fail (SWFDEC_IS_PLAYER (player
), NULL
);
1780 g_return_val_if_fail (level
>= 0, NULL
);
1781 g_return_val_if_fail (swfdec_player_get_movie_at_level (player
, level
) == NULL
, NULL
);
1783 /* create new root movie */
1784 s
= swfdec_as_context_give_string (SWFDEC_AS_CONTEXT (player
), g_strdup_printf ("_level%d", level
));
1785 movie
= swfdec_movie_new (player
, level
- 16384, NULL
, resource
, NULL
, s
);
1788 movie
->name
= SWFDEC_AS_STR_EMPTY
;
1789 return SWFDEC_SPRITE_MOVIE (movie
);
1793 * swfdec_player_get_movie_at_level:
1794 * @player: a #SwfdecPlayer
1795 * @level: number of the level
1797 * This function is used to look up root movies in the given @player.
1799 * Returns: the #SwfdecMovie located at the given level or %NULL if there is no
1800 * movie at that level.
1803 swfdec_player_get_movie_at_level (SwfdecPlayer
*player
, int level
)
1808 g_return_val_if_fail (SWFDEC_IS_PLAYER (player
), NULL
);
1809 g_return_val_if_fail (level
>= 0, NULL
);
1811 depth
= level
- 16384;
1813 for (walk
= player
->roots
; walk
; walk
= walk
->next
) {
1814 SwfdecMovie
*cur
= walk
->data
;
1815 if (cur
->depth
< depth
)
1817 if (cur
->depth
== depth
)
1818 return SWFDEC_SPRITE_MOVIE (cur
);
1825 swfdec_player_launch (SwfdecPlayer
*player
, SwfdecLoaderRequest request
, const char *url
,
1826 const char *target
, SwfdecBuffer
*data
)
1828 g_return_if_fail (SWFDEC_IS_PLAYER (player
));
1829 g_return_if_fail (url
!= NULL
);
1830 g_return_if_fail (target
!= NULL
);
1832 if (!g_ascii_strncasecmp (url
, "FSCommand:", strlen ("FSCommand:"))) {
1833 const char *command
= url
+ strlen ("FSCommand:");
1834 g_signal_emit (player
, signals
[FSCOMMAND
], 0, command
, target
);
1837 g_signal_emit (player
, signals
[LAUNCH
], 0, (int) request
, url
, target
, data
);
1841 * swfdec_player_initialize:
1842 * @player: a #SwfdecPlayer
1843 * @version: Flash version to use
1844 * @rate: framerate in 256th or 0 for undefined
1845 * @width: width of movie
1846 * @height: height of movie
1848 * Initializes the player to the given @version, @width, @height and @rate. If
1849 * the player is already initialized, this function does nothing.
1852 swfdec_player_initialize (SwfdecPlayer
*player
, guint version
,
1853 guint rate
, guint width
, guint height
)
1855 g_return_if_fail (SWFDEC_IS_PLAYER (player
));
1856 g_return_if_fail (rate
> 0);
1858 if (!player
->initialized
) {
1859 SwfdecAsContext
*context
= SWFDEC_AS_CONTEXT (player
);
1860 swfdec_as_context_startup (context
, version
);
1861 /* reset state for initialization */
1862 /* FIXME: have a better way to do this */
1863 if (context
->state
== SWFDEC_AS_CONTEXT_RUNNING
) {
1864 context
->state
= SWFDEC_AS_CONTEXT_NEW
;
1865 swfdec_sprite_movie_init_context (player
, version
);
1866 swfdec_video_movie_init_context (player
, version
);
1867 swfdec_net_connection_init_context (player
, version
);
1868 swfdec_net_stream_init_context (player
, version
);
1870 swfdec_as_context_run_init_script (context
, swfdec_initialize
,
1871 sizeof (swfdec_initialize
), 8);
1873 if (context
->state
== SWFDEC_AS_CONTEXT_NEW
) {
1874 context
->state
= SWFDEC_AS_CONTEXT_RUNNING
;
1875 swfdec_as_object_set_constructor (player
->roots
->data
, player
->MovieClip
);
1878 player
->initialized
= TRUE
;
1879 g_object_notify (G_OBJECT (player
), "initialized");
1881 /* FIXME: need to kick all other movies out here */
1882 swfdec_player_remove_timeout (player
, &player
->iterate_timeout
);
1885 SWFDEC_INFO ("initializing player to size %ux%u and rate %u/256", width
, height
, rate
);
1886 if (rate
!= player
->rate
) {
1887 player
->rate
= rate
;
1888 g_object_notify (G_OBJECT (player
), "rate");
1890 if (player
->width
!= width
) {
1891 player
->width
= width
;
1892 g_object_notify (G_OBJECT (player
), "default-width");
1894 if (player
->height
!= height
) {
1895 player
->height
= height
;
1896 g_object_notify (G_OBJECT (player
), "default-height");
1898 player
->internal_width
= player
->stage_width
>= 0 ? (guint
) player
->stage_width
: player
->width
;
1899 player
->internal_height
= player
->stage_height
>= 0 ? (guint
) player
->stage_height
: player
->height
;
1900 swfdec_player_update_scale (player
);
1902 player
->iterate_timeout
.timestamp
= player
->time
+ SWFDEC_TICKS_PER_SECOND
* 256 / player
->rate
/ 10;
1903 swfdec_player_add_timeout (player
, &player
->iterate_timeout
);
1904 SWFDEC_LOG ("initialized iterate timeout %p to %"G_GUINT64_FORMAT
" (now %"G_GUINT64_FORMAT
")",
1905 &player
->iterate_timeout
, player
->iterate_timeout
.timestamp
, player
->time
);
1909 * swfdec_player_get_export_class:
1910 * @player: a #SwfdecPlayer
1911 * @name: garbage-collected string naming the export
1913 * Looks up the constructor for characters that are exported using @name.
1915 * Returns: a #SwfdecAsObject naming the constructor or %NULL if none
1918 swfdec_player_get_export_class (SwfdecPlayer
*player
, const char *name
)
1920 SwfdecAsObject
*ret
;
1922 ret
= g_hash_table_lookup (player
->registered_classes
, name
);
1924 SWFDEC_LOG ("found registered class %p for %s", ret
, name
);
1927 return player
->MovieClip
;
1931 * swfdec_player_set_export_class:
1932 * @player: a #SwfdecPlayer
1933 * @name: garbage-collected string naming the export
1934 * @object: object to use as constructor or %NULL for none
1936 * Sets the constructor to be used for instances created using the object
1937 * exported with @name.
1940 swfdec_player_set_export_class (SwfdecPlayer
*player
, const char *name
, SwfdecAsObject
*object
)
1942 g_return_if_fail (SWFDEC_IS_PLAYER (player
));
1943 g_return_if_fail (name
!= NULL
);
1944 g_return_if_fail (object
== NULL
|| SWFDEC_IS_AS_OBJECT (object
));
1947 SWFDEC_LOG ("setting class %p for %s", object
, name
);
1948 g_hash_table_insert (player
->registered_classes
, (gpointer
) name
, object
);
1950 g_hash_table_remove (player
->registered_classes
, name
);
1955 * I don't like the idea of rooting arbitrary objects very much. And so far,
1956 * this API is only necessary for the objects used for loading data. So it seems
1957 * like a good idea to revisit the refcounting and GCing of resources.
1960 swfdec_player_root_object (SwfdecPlayer
*player
, GObject
*object
)
1962 g_return_if_fail (SWFDEC_IS_PLAYER (player
));
1963 g_return_if_fail (G_IS_OBJECT (object
));
1965 g_object_ref (object
);
1966 player
->rooted_objects
= g_list_prepend (player
->rooted_objects
, object
);
1970 swfdec_player_unroot_object (SwfdecPlayer
*player
, GObject
*object
)
1974 g_return_if_fail (SWFDEC_IS_PLAYER (player
));
1975 g_return_if_fail (G_IS_OBJECT (object
));
1976 entry
= g_list_find (player
->rooted_objects
, object
);
1977 g_return_if_fail (entry
!= NULL
);
1978 g_object_unref (object
);
1979 player
->rooted_objects
= g_list_delete_link (player
->rooted_objects
, entry
);
1985 * swfdec_player_new:
1986 * @debugger: %NULL or a #SwfdecAsDebugger to use for debugging this player.
1988 * Creates a new player. This function is supposed to be used for testing.
1989 * Because of this, the created player will behave as predictable as possible.
1990 * For example, it will generate the same random number sequence every time.
1991 * The function calls swfdec_init () for you if it wasn't called before.
1993 * Returns: The new player
1996 swfdec_player_new (SwfdecAsDebugger
*debugger
)
1998 static const GTimeVal the_beginning
= { 1035840244, 0 };
1999 SwfdecPlayer
*player
;
2001 g_return_val_if_fail (debugger
== NULL
|| SWFDEC_IS_AS_DEBUGGER (debugger
), NULL
);
2004 player
= g_object_new (SWFDEC_TYPE_PLAYER
, "random-seed", 0,
2006 "debugger", debugger
, NULL
);
2007 /* FIXME: make this a property or something and don't set it here */
2008 SWFDEC_AS_CONTEXT (player
)->start_time
= the_beginning
;
2014 * swfdec_player_set_loader:
2015 * @player: a #SwfdecPlayer
2016 * @loader: the loader to use for this player. Takes ownership of the given loader.
2018 * Sets the loader for the main data. This function only works if no loader has
2019 * been set on @player yet.
2020 * For details, see swfdec_player_set_loader_with_variables().
2023 swfdec_player_set_loader (SwfdecPlayer
*player
, SwfdecLoader
*loader
)
2025 g_return_if_fail (SWFDEC_IS_PLAYER (player
));
2026 g_return_if_fail (player
->roots
== NULL
);
2027 g_return_if_fail (SWFDEC_IS_LOADER (loader
));
2029 swfdec_player_set_loader_with_variables (player
, loader
, NULL
);
2033 * swfdec_player_set_loader_with_variables:
2034 * @player: a #SwfdecPlayer
2035 * @loader: the loader to use for this player. Takes ownership of the given loader.
2036 * @variables: a string that is checked to be in 'application/x-www-form-urlencoded'
2037 * syntax describing the arguments to set on the new player or NULL for
2040 * Sets the loader for the main data. This function only works if no loader has
2041 * been set on @player yet.
2042 * If the @variables are set and validate, they will be set as properties on the
2046 swfdec_player_set_loader_with_variables (SwfdecPlayer
*player
, SwfdecLoader
*loader
,
2047 const char *variables
)
2051 g_return_if_fail (SWFDEC_IS_PLAYER (player
));
2052 g_return_if_fail (player
->resource
== NULL
);
2053 g_return_if_fail (SWFDEC_IS_LOADER (loader
));
2055 player
->resource
= swfdec_resource_new (player
, loader
, variables
);
2056 movie
= swfdec_movie_new (player
, -16384, NULL
, player
->resource
, NULL
, SWFDEC_AS_STR__level0
);
2057 movie
->name
= SWFDEC_AS_STR_EMPTY
;
2058 g_object_unref (loader
);
2062 * swfdec_player_new_from_file:
2063 * @filename: name of the file to play
2065 * Creates a player to play back the given file. If the file does not
2066 * exist or another error occurs, the player will be in an error state and not
2068 * This function calls swfdec_init () for you if it wasn't called before.
2070 * Returns: a new player
2073 swfdec_player_new_from_file (const char *filename
)
2075 SwfdecLoader
*loader
;
2076 SwfdecPlayer
*player
;
2078 g_return_val_if_fail (filename
!= NULL
, NULL
);
2080 loader
= swfdec_file_loader_new (filename
);
2081 player
= swfdec_player_new (NULL
);
2082 swfdec_player_set_loader (player
, loader
);
2090 * Initializes the Swfdec library.
2095 static gboolean _inited
= FALSE
;
2103 if (!g_thread_supported ())
2104 g_thread_init (NULL
);
2108 s
= g_getenv ("SWFDEC_DEBUG");
2113 level
= strtoul (s
, &end
, 0);
2115 swfdec_debug_set_level (level
);
2121 * swfdec_player_handle_mouse:
2122 * @player: a #SwfdecPlayer
2123 * @x: x coordinate of mouse
2124 * @y: y coordinate of mouse
2125 * @button: 1 for pressed, 0 for not pressed
2127 * Updates the current mouse status. If the mouse has left the area of @player,
2128 * you should pass values outside the movie size for @x and @y. You will
2129 * probably want to call swfdec_player_advance() before to update the player to
2130 * the correct time when calling this function.
2132 * Returns: %TRUE if the mouse event was handled. %FALSE to propagate the event
2133 * further. A mouse event may not be handled if the user clicked on a
2137 swfdec_player_handle_mouse (SwfdecPlayer
*player
,
2138 double x
, double y
, int button
)
2142 g_return_val_if_fail (SWFDEC_IS_PLAYER (player
), FALSE
);
2143 g_return_val_if_fail (button
== 0 || button
== 1, FALSE
);
2145 g_signal_emit (player
, signals
[HANDLE_MOUSE
], 0, x
, y
, button
, &ret
);
2151 * swfdec_player_key_press:
2152 * @player: a #SwfdecPlayer
2153 * @keycode: the key that was pressed
2154 * @character: UCS4 of the character that was inserted or 0 if none
2156 * Call this function to make the @player react to a key press. Be sure to
2157 * check that keycode transformations are done correctly. For a list of
2158 * keycodes see FIXME.
2160 * Returns: %TRUE if the key press was handled by the @player, %FALSE if it
2161 * should be propagated further
2164 swfdec_player_key_press (SwfdecPlayer
*player
, guint keycode
, guint character
)
2168 g_return_val_if_fail (SWFDEC_IS_PLAYER (player
), FALSE
);
2169 g_return_val_if_fail (keycode
< 256, FALSE
);
2171 g_signal_emit (player
, signals
[HANDLE_KEY
], 0, keycode
, character
, TRUE
, &ret
);
2177 * swfdec_player_key_release:
2178 * @player: a #SwfdecPlayer
2179 * @keycode: the key that was released
2180 * @character: UCS4 of the character that was inserted or 0 if none
2182 * Call this function to make the @player react to a key being released. See
2183 * swfdec_player_key_press() for details.
2185 * Returns: %TRUE if the key press was handled by the @player, %FALSE if it
2186 * should be propagated further
2189 swfdec_player_key_release (SwfdecPlayer
*player
, guint keycode
, guint character
)
2193 g_return_val_if_fail (SWFDEC_IS_PLAYER (player
), FALSE
);
2194 g_return_val_if_fail (keycode
< 256, FALSE
);
2196 g_signal_emit (player
, signals
[HANDLE_KEY
], 0, keycode
, character
, FALSE
, &ret
);
2202 * swfdec_player_render:
2203 * @player: a #SwfdecPlayer
2204 * @cr: #cairo_t to render to
2205 * @x: x coordinate of top left position to render
2206 * @y: y coordinate of top left position to render
2207 * @width: width of area to render or 0 for full width
2208 * @height: height of area to render or 0 for full height
2210 * Renders the given area of the current frame to @cr.
2213 swfdec_player_render (SwfdecPlayer
*player
, cairo_t
*cr
,
2214 double x
, double y
, double width
, double height
)
2216 static const SwfdecColorTransform trans
= { 256, 0, 256, 0, 256, 0, 256, 0 };
2220 g_return_if_fail (SWFDEC_IS_PLAYER (player
));
2221 g_return_if_fail (cr
!= NULL
);
2222 g_return_if_fail (width
>= 0.0);
2223 g_return_if_fail (height
>= 0.0);
2225 /* FIXME: fail when !initialized? */
2226 if (!swfdec_player_is_initialized (player
))
2230 width
= player
->stage_width
;
2232 height
= player
->stage_height
;
2235 cairo_rectangle (cr
, x
, y
, width
, height
);
2237 /* compute the rectangle */
2238 x
-= player
->offset_x
;
2239 y
-= player
->offset_y
;
2240 real
.x0
= floor (x
* SWFDEC_TWIPS_SCALE_FACTOR
) / player
->scale_x
;
2241 real
.y0
= floor (y
* SWFDEC_TWIPS_SCALE_FACTOR
) / player
->scale_y
;
2242 real
.x1
= ceil ((x
+ width
) * SWFDEC_TWIPS_SCALE_FACTOR
) / player
->scale_x
;
2243 real
.y1
= ceil ((y
+ height
) * SWFDEC_TWIPS_SCALE_FACTOR
) / player
->scale_y
;
2244 SWFDEC_INFO ("=== %p: START RENDER, area %g %g %g %g ===", player
,
2245 real
.x0
, real
.y0
, real
.x1
, real
.y1
);
2246 /* convert the cairo matrix */
2247 cairo_translate (cr
, player
->offset_x
, player
->offset_y
);
2248 cairo_scale (cr
, player
->scale_x
/ SWFDEC_TWIPS_SCALE_FACTOR
, player
->scale_y
/ SWFDEC_TWIPS_SCALE_FACTOR
);
2249 swfdec_color_set_source (cr
, player
->bgcolor
);
2252 for (walk
= player
->roots
; walk
; walk
= walk
->next
) {
2253 swfdec_movie_render (walk
->data
, cr
, &trans
, &real
);
2255 SWFDEC_INFO ("=== %p: END RENDER ===", player
);
2260 * swfdec_player_advance:
2261 * @player: the #SwfdecPlayer to advance
2262 * @msecs: number of milliseconds to advance
2264 * Advances @player by @msecs. You should make sure to call this function as
2265 * often as the SwfdecPlayer::next-event property indicates.
2268 swfdec_player_advance (SwfdecPlayer
*player
, gulong msecs
)
2271 g_return_if_fail (SWFDEC_IS_PLAYER (player
));
2273 frames
= SWFDEC_TICKS_TO_SAMPLES (player
->time
+ SWFDEC_MSECS_TO_TICKS (msecs
))
2274 - SWFDEC_TICKS_TO_SAMPLES (player
->time
);
2275 g_signal_emit (player
, signals
[ADVANCE
], 0, msecs
, frames
);
2279 * swfdec_player_is_initialized:
2280 * @player: a #SwfdecPlayer
2282 * Determines if the @player is initalized yet. An initialized player is able
2283 * to provide basic values like width, height or rate. A player may not be
2284 * initialized if the loader it was started with does not reference a Flash
2285 * resources or it did not provide enough data yet. If a player is initialized,
2286 * it will never be uninitialized again.
2288 * Returns: TRUE if the basic values are known.
2291 swfdec_player_is_initialized (SwfdecPlayer
*player
)
2293 g_return_val_if_fail (SWFDEC_IS_PLAYER (player
), FALSE
);
2295 return player
->initialized
;
2299 * swfdec_player_get_next_event:
2300 * @player: ia #SwfdecPlayer
2302 * Queries how long to the next event. This is the next time when you should
2303 * call swfdec_player_advance() to forward to.
2305 * Returns: number of milliseconds until next event or -1 if no outstanding event
2308 swfdec_player_get_next_event (SwfdecPlayer
*player
)
2313 g_return_val_if_fail (SWFDEC_IS_PLAYER (player
), 0);
2315 if (swfdec_as_context_is_aborted (SWFDEC_AS_CONTEXT (player
)))
2318 tick
= swfdec_player_get_next_event_time (player
);
2319 if (tick
== G_MAXUINT64
)
2321 /* round up to full msecs */
2322 ret
= SWFDEC_TICKS_TO_MSECS (tick
+ SWFDEC_TICKS_PER_SECOND
/ 1000 - 1);
2328 * swfdec_player_get_rate:
2329 * @player: a #SwfdecPlayer
2331 * Queries the framerate of this movie. This number specifies the number
2332 * of frames that are supposed to pass per second. It is a
2333 * multiple of 1/256. It is possible that the movie has no framerate if it does
2334 * not display a Flash movie but an FLV video for example. This does not mean
2335 * it will not change however.
2337 * Returns: The framerate of this movie or 0 if it isn't known yet or the
2338 * movie doesn't have a framerate.
2341 swfdec_player_get_rate (SwfdecPlayer
*player
)
2343 g_return_val_if_fail (SWFDEC_IS_PLAYER (player
), 0.0);
2345 return player
->rate
/ 256.0;
2349 * swfdec_player_get_default_size:
2350 * @player: a #SwfdecPlayer
2351 * @width: integer to store the width in or %NULL
2352 * @height: integer to store the height in or %NULL
2354 * If the default size of the movie is initialized, fills in @width and @height
2355 * with the size. Otherwise @width and @height are set to 0.
2358 swfdec_player_get_default_size (SwfdecPlayer
*player
, guint
*width
, guint
*height
)
2360 g_return_if_fail (SWFDEC_IS_PLAYER (player
));
2363 *width
= player
->width
;
2365 *height
= player
->height
;
2369 * swfdec_player_get_size:
2370 * @player: a #SwfdecPlayer
2371 * @width: integer to store the width in or %NULL
2372 * @height: integer to store the height in or %NULL
2374 * Gets the currently set image size. If the default width or height should be
2375 * used, the width or height respectively is set to -1.
2378 swfdec_player_get_size (SwfdecPlayer
*player
, int *width
, int *height
)
2380 g_return_if_fail (SWFDEC_IS_PLAYER (player
));
2383 *width
= player
->stage_width
;
2385 *height
= player
->stage_height
;
2389 swfdec_player_update_size (gpointer playerp
, gpointer unused
)
2391 SwfdecPlayer
*player
= playerp
;
2392 guint width
, height
;
2394 /* FIXME: only update if not fullscreen */
2395 width
= player
->stage_width
>=0 ? (guint
) player
->stage_width
: player
->width
;
2396 height
= player
->stage_height
>=0 ? (guint
) player
->stage_height
: player
->height
;
2397 /* only broadcast once */
2398 if (width
== player
->internal_width
&& height
== player
->internal_height
)
2401 player
->internal_width
= width
;
2402 player
->internal_height
= height
;
2403 if (player
->scale_mode
== SWFDEC_SCALE_NONE
)
2404 swfdec_player_broadcast (player
, SWFDEC_AS_STR_Stage
, SWFDEC_AS_STR_onResize
);
2408 * swfdec_player_set_size:
2409 * @player: a #SwfdecPlayer
2410 * @width: desired width of the movie or -1 for default
2411 * @height: desired height of the movie or -1 for default
2413 * Sets the image size to the given values. The image size is what the area that
2414 * the @player will render and advocate with scripts.
2417 swfdec_player_set_size (SwfdecPlayer
*player
, int width
, int height
)
2419 gboolean changed
= FALSE
;
2421 g_return_if_fail (SWFDEC_IS_PLAYER (player
));
2422 g_return_if_fail (width
>= -1);
2423 g_return_if_fail (height
>= -1);
2425 if (player
->stage_width
!= width
) {
2426 player
->stage_width
= width
;
2427 g_object_notify (G_OBJECT (player
), "width");
2430 if (player
->stage_height
!= height
) {
2431 player
->stage_height
= height
;
2432 g_object_notify (G_OBJECT (player
), "height");
2435 swfdec_player_update_scale (player
);
2437 swfdec_player_add_external_action (player
, player
, swfdec_player_update_size
, NULL
);
2441 * swfdec_player_get_audio:
2442 * @player: a #SwfdecPlayer
2444 * Returns a list of all currently active audio streams in @player.
2446 * Returns: A #GList of #SwfdecAudio. You must not modify or free this list.
2448 /* FIXME: I don't like this function */
2450 swfdec_player_get_audio (SwfdecPlayer
* player
)
2452 g_return_val_if_fail (SWFDEC_IS_PLAYER (player
), NULL
);
2454 return player
->audio
;
2458 * swfdec_player_get_background_color:
2459 * @player: a #SwfdecPlayer
2461 * Gets the current background color. The color will be an ARGB-quad, with the
2462 * MSB being the alpha value.
2464 * Returns: the background color as an ARGB value
2467 swfdec_player_get_background_color (SwfdecPlayer
*player
)
2469 g_return_val_if_fail (SWFDEC_IS_PLAYER (player
), SWFDEC_COLOR_COMBINE (0xFF, 0xFF, 0xFF, 0xFF));
2471 return player
->bgcolor
;
2475 * swfdec_player_set_background_color:
2476 * @player: a #SwfdecPlayer
2477 * @color: new color to use as background color
2479 * Sets a new background color as an ARGB value. To get transparency, set the
2480 * value to 0. To get a black beackground, use 0xFF000000.
2483 swfdec_player_set_background_color (SwfdecPlayer
*player
, guint color
)
2485 g_return_if_fail (SWFDEC_IS_PLAYER (player
));
2487 player
->bgcolor_set
= TRUE
;
2488 if (player
->bgcolor
== color
)
2490 player
->bgcolor
= color
;
2491 g_object_notify (G_OBJECT (player
), "background-color");
2492 if (swfdec_player_is_initialized (player
)) {
2493 g_signal_emit (player
, signals
[INVALIDATE
], 0, 0.0, 0.0,
2494 (double) player
->width
, (double) player
->height
);
2499 * swfdec_player_get_scale_mode:
2500 * @player: a #SwfdecPlayer
2502 * Gets the currrent mode used for scaling the movie. See #SwfdecScaleMode for
2503 * the different modes.
2505 * Returns: the current scale mode
2508 swfdec_player_get_scale_mode (SwfdecPlayer
*player
)
2510 g_return_val_if_fail (SWFDEC_IS_PLAYER (player
), SWFDEC_SCALE_SHOW_ALL
);
2512 return player
->scale_mode
;
2516 * swfdec_player_set_scale_mode:
2517 * @player: a #SwfdecPlayer
2518 * @mode: a #SwfdecScaleMode
2520 * Sets the currrent mode used for scaling the movie. See #SwfdecScaleMode for
2521 * the different modes.
2524 swfdec_player_set_scale_mode (SwfdecPlayer
*player
, SwfdecScaleMode mode
)
2526 g_return_if_fail (SWFDEC_IS_PLAYER (player
));
2528 if (player
->scale_mode
!= mode
) {
2529 player
->scale_mode
= mode
;
2530 swfdec_player_update_scale (player
);
2531 g_object_notify (G_OBJECT (player
), "scale-mode");
2536 * swfdec_player_get_alignment:
2537 * @player: a #SwfdecPlayer
2539 * Gets the alignment of the player. The alignment describes what point is used
2540 * as the anchor for drawing the contents. See #SwfdecAlignment for possible
2543 * Returns: the current alignment
2546 swfdec_player_get_alignment (SwfdecPlayer
*player
)
2548 g_return_val_if_fail (SWFDEC_IS_PLAYER (player
), SWFDEC_ALIGNMENT_CENTER
);
2550 return swfdec_player_alignment_from_flags (player
->align_flags
);
2554 * swfdec_player_set_alignment:
2555 * @player: a #SwfdecPlayer
2556 * @align: #SwfdecAlignment to set
2558 * Sets the alignment to @align. For details about alignment, see
2559 * swfdec_player_get_alignment() and #SwfdecAlignment.
2562 swfdec_player_set_alignment (SwfdecPlayer
*player
, SwfdecAlignment align
)
2566 g_return_if_fail (SWFDEC_IS_PLAYER (player
));
2568 flags
= swfdec_player_alignment_to_flags (align
);
2569 swfdec_player_set_align_flags (player
, flags
);
2573 swfdec_player_set_align_flags (SwfdecPlayer
*player
, guint flags
)
2575 g_return_if_fail (SWFDEC_IS_PLAYER (player
));
2577 if (flags
!= player
->align_flags
) {
2578 player
->align_flags
= flags
;
2579 swfdec_player_update_scale (player
);
2580 g_object_notify (G_OBJECT (player
), "alignment");
2585 * swfdec_player_get_maximum_runtime:
2586 * @player: a #SwfdecPlayer
2588 * Queries the given @player for how long scripts may run. see
2589 * swfdec_player_set_maximum_runtime() for a longer discussion of this value.
2591 * Returns: the maximum time in milliseconds that scripts are allowed to run or
2595 swfdec_player_get_maximum_runtime (SwfdecPlayer
*player
)
2597 g_return_val_if_fail (SWFDEC_IS_PLAYER (player
), 0);
2599 return player
->max_runtime
;
2603 * swfdec_player_set_maximum_runtime:
2604 * @player: a #SwfdecPlayer
2605 * @msecs: time in milliseconds that scripts are allowed to run or 0 for
2608 * Sets the time that the player may use to let internal scripts run. If the
2609 * Flash file that is currently played back does not manage to complete its
2610 * scripts in the given time, it is aborted. You cannot continue the scripts at
2611 * a later point in time. However, your application may become unresponsive and
2612 * your users annoyed if they cannot interact with it for too long. To give a
2613 * reference point, the Adobe Flash player usually sets this value to 10
2614 * seconds. Note that this time determines the maximum time calling
2615 * swfdec_player_advance() may take, even if it is called with a large value.
2616 * Also note that this setting is ignored when running inside a debugger.
2619 swfdec_player_set_maximum_runtime (SwfdecPlayer
*player
, gulong msecs
)
2621 g_return_if_fail (SWFDEC_IS_PLAYER (player
));
2623 player
->max_runtime
= msecs
;
2624 g_object_notify (G_OBJECT (player
), "max-runtime");