2 // Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012
3 // Free Software Foundation, Inc
5 // This program is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation; either version 3 of the License, or
8 // (at your option) any later version.
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
15 // You should have received a copy of the GNU General Public License
16 // along with this program; if not, write to the Free Software
17 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20 /// \page events_handling Handling of user events
22 /// There are two kinds of events:
23 /// - system generated
26 /// System generated events are those like load, data recive, unload,
28 /// User generated events are mouse movements and clicks, keyboard activity.
30 /// Events can trigger actions execution, if "handlers" are specified for
31 /// a specific event with ActionScript code.
32 /// The actions triggered by user events are executed *immediately*, not
33 /// at the next frame iteration. Nonetheless, since rendering of the stage
34 /// usually happens at fixed rate (frame rate) you won't see the effects
35 /// of actions execution until next iteration... unless...
37 /// Well, *some* events actions always trigger immediate redisplay, while
38 /// some others require a call to a special function to do so.
40 /// The events actions that trigger immediate redisplay are Button actions.
41 /// Colin Mook, in his "ActionScript - The Definitive Guide" sais:
42 /// << Buttons naturally update between frames >>
44 /// Other events, in particular MovieClip events such as mouseDown, mouseUp,
45 /// mouseMove, keyDown and keyUp don't by default trigger redisplay, unless
46 /// the attached action code makes a call to the special function named
47 /// 'updateAfterEvent()'.
49 /// For this purpose, user events notification functions in gnash core
50 /// library return a boolean value, which tells wheter any action triggered
51 /// by the event requires immediate redisplay.
53 /// At the time of writing (2006-10-19) this is not implemented yet and
54 /// the return code is always TRUE. We shall work on it :)
56 /// The events notification functions that currently support this interface
59 /// - bool movie_root::notify_mouse_moved(int x, int y);
60 /// - bool movie_root::notify_mouse_clicked(bool mouse_pressed, int mask);
61 /// - bool keyEvent(key::code k, bool down);
64 #ifndef GNASH_MOVIE_ROOT_H
65 #define GNASH_MOVIE_ROOT_H
68 #include "gnashconfig.h" //USE_SWFTREE
74 #include <forward_list>
78 #include <boost/ptr_container/ptr_deque.hpp>
79 #include <boost/noncopyable.hpp>
80 #include <boost/any.hpp>
81 #include <boost/optional.hpp>
83 #include "dsodefs.h" // DSOEXPORT
84 #include "DragState.h"
85 #include "MouseButtonState.h" // for composition
86 #include "GnashKey.h" // key::code
87 #include "GnashEnums.h"
88 #include "MovieClip.h"
89 #include "SimpleBuffer.h" // for LoadCallback
90 #include "MovieLoader.h"
91 #include "ExternalInterface.h"
94 #include "HostInterface.h"
96 #include "IOChannel.h"
102 // GNASH_PARANOIA_LEVEL:
103 // 0 : (not unimplemented)
104 // 1 : quick assertions
105 // 2 : add testInvariant
107 #ifndef GNASH_PARANOIA_LEVEL
108 # define GNASH_PARANOIA_LEVEL 1
111 // Forward declarations
113 class ExecutableCode
;
126 struct DepthComparator
128 typedef MovieClip
* LevelMovie
;
129 bool operator()(const LevelMovie
& d1
, const LevelMovie
& d2
) const {
130 return d1
->get_depth() < d2
->get_depth();
134 /// This class represents the 'Stage' and top-level movie.
136 /// It is a wrapper around the set of loaded levels being played. Each
137 /// 'run' of a SWF movie, including all further movies loaded during the
138 /// run, has exactly one movie_root, which is kept for the entire run.
139 /// Loading a new top-level movie does not create a new movie_root.
141 /// The 'Stage' part of movie_root is accessible through the ActionScript
142 /// Stage object, implemented in Stage_as.cpp.
144 /// The movie_root class is responsible for accepting and passing on
145 /// user events (mouse or key events), for maintaining the heart-beat
146 /// mechanism, and for advancing all MovieClips on request from the
147 /// hosting application.
149 /// The _root object is provided by getAsRoot().
150 class DSOEXPORT movie_root
: public GcRoot
, boost::noncopyable
156 LoadCallback(std::unique_ptr
<IOChannel
> s
, as_object
* o
)
158 _stream(std::move(s
)),
162 void setReachable() const;
164 std::unique_ptr
<IOChannel
> _stream
;
168 typedef std::list
<LoadCallback
> LoadCallbacks
;
170 typedef std::bitset
<key::KEYCOUNT
> Keys
;
172 /// Default constructor
174 /// Make sure to call setRootMovie()
175 /// before using any of this class methods !
176 movie_root(VirtualClock
& clock
, const RunResources
& runResources
);
180 /// Initialize movie_root with a parsed movie definition
182 /// The definition may be a SWF or Bitmap movie definition.
184 /// The created Movie is returned; it is non-const so may be stored,
185 /// queried, and changed by the caller for debugging or manipulation.
186 /// Direct use of the pointer may result in unexpected behaviour during
187 /// SWF playback, so for normal playback this pointer should not be
189 Movie
* init(movie_definition
* def
,
190 const MovieClip::MovieVariables
& variables
);
192 /// Return the movie at the given level (0 if unloaded level).
195 /// - The returned DisplayObject has a depth equal to 'num'
197 MovieClip
* getLevel(unsigned int num
) const;
199 /// Put the given movie at the given level
202 /// The Movie to store at the given level.
203 /// Its depth will be set to <num>+DisplayObject::staticDepthOffset and
204 /// its name to _level<num>
205 void setLevel(unsigned int num
, Movie
* movie
);
207 /// Replace an existing level with a new movie
209 /// Depth will be assigned to external_movie by this function.
210 /// If the give level number doesn't exist an error is logged
211 /// and nothing else happens.
213 /// This method is intended for use by xxx.loadMovie(yyy)
214 /// when 'xxx' is a top-level movie.
216 void replaceLevel(unsigned int num
, Movie
* external_movie
);
218 /// Swap depth of a level (or two)
220 /// Character's depths are updated.
223 /// The level to change depth/level of. A pointer to it is expected
224 /// to be found in the _level# container, or an error will be printed
225 /// and the call would result in a no-op.
228 /// New depth to assign to the DisplayObject. If another level
229 /// exists at the target depth the latter is moved in place of
230 /// the former, with its depth also updated.
232 void swapLevels(MovieClip
* sp
, int depth
);
234 /// Drop level at given depth.
237 /// Depth of the level to drop. Note that this is
238 /// -DisplayObject::staticDepthOffset for the root movie. Must be >=0 and
239 /// <= 1048575 or an assertion will fail. Note that if the depth
240 /// evaluates to the original root movie nothing happens (not allowed
241 /// to remove that). It is not tested if it's allowed to remove _level0
242 /// after loading into it.
243 void dropLevel(int depth
);
245 /// Change stage size
247 /// This may be smaller than the size of the root movie. It determines
248 /// how much of the movie is visible.
250 /// @param w The width of the stage
251 /// @param h The height of the stage.
252 void setDimensions(size_t w
, size_t h
);
254 /// Notional width of the stage, actual value depending on scaleMode
255 size_t getStageWidth() const;
257 /// Notional height of the stage, actual value depending on scaleMode
258 size_t getStageHeight() const;
260 /// Inform the Stage that the mouse has moved.
262 /// Coordinates are in Stage Coordinate Space (pseudo-pixels units).
264 /// @param x The x co-ordinate in pixels.
265 /// @param y The y co-ordinate in pixels.
266 /// @return true if any action triggered requires a redraw.
268 /// TODO: take twips (or float pixels), or we won't be able to
269 /// support sub-pixel accuracy in collision detection.
270 DSOEXPORT
bool mouseMoved(std::int32_t x
, std::int32_t y
);
272 /// Inform the Stage that a mouse click has occurred.
274 /// @param press true for a mouse click, false for a release
275 /// @return true if any action triggered requires a redraw.
276 DSOEXPORT
bool mouseClick(bool press
);
278 /// Inform the Stage that a mouse wheel has moved.
280 /// @param delta The direction of the scroll: positive for up, negative
281 /// for down. Although values from about -3 to 3 are
282 /// documented, only -1 and 1 have been observed.
283 /// @return true if any action triggered requires a redraw.
284 DSOEXPORT
bool mouseWheel(int delta
);
286 /// Tell the movie when the user pressed or released a key.
288 /// This function should return TRUE if any action triggered
289 /// by the event requires redraw, see \ref events_handling for
291 DSOEXPORT
bool keyEvent(key::code k
, bool down
);
293 /// Use this to retrieve the last state of the mouse.
295 /// Coordinates are in PIXELS, NOT TWIPS.
296 std::pair
<std::int32_t, std::int32_t> mousePosition() const;
298 void setDragState(const DragState
& st
);
300 /// Access the originating root movie (not necessarily _level0)
302 /// @return the original root movie.
303 Movie
& getRootMovie() {
311 /// Add an interval timer
314 /// A Timer, ownership will be transferred. Must not be NULL.
317 /// If true, this is an internal timer, so will get a negative id.
319 /// @return An integer indentifying the timer
320 /// for subsequent call to clear_interval_timer.
321 /// It will NEVER be zero.
322 std::uint32_t addIntervalTimer(std::unique_ptr
<Timer
> timer
);
324 /// Register an object for loading data to.
326 /// When complete, the object's onData function is called.
327 /// The callback is removed when the load is complete, including failed
330 /// There is no restriction on the type of as_object that can registered.
332 /// @param obj The object to update when data is received.
333 /// @param str The stream to load from.
335 /// TODO: this function could be improved, e.g. by handling the
336 /// URL checking and stream construction as well.
338 /// It may be possible for this function to handle all connections if
339 /// it also takes a callback function to call on each advance.
340 void addLoadableObject(as_object
* obj
, std::unique_ptr
<IOChannel
> str
);
342 void addAdvanceCallback(ActiveRelay
* obj
);
344 void removeAdvanceCallback(ActiveRelay
* obj
);
346 /// Remove timer identified by given integer
348 /// @return true on success, false on error (no such timer)
349 bool clearIntervalTimer(std::uint32_t x
);
351 void set_background_color(const rgba
& color
);
353 void set_background_alpha(float alpha
);
355 /// Return the VM used by this movie_root
356 VM
& getVM() { return _vm
; }
358 /// Main and only callback from hosting application.
359 /// Expected to be called at 10ms resolution.
361 /// @return true if the heart-beat resulted in actual
362 /// SWF playhead advancement (frame advancement)
367 /// Return the number of milliseconds available before
368 /// it's time to advance the timeline again.
370 /// Return value can be negative if we're late...
372 int timeToNextFrame() const;
374 /// Entry point for movie advancement
376 /// This function does:
377 /// - Execute all timers
378 /// - Reset the next Random number
379 /// - Advance all advanceable DisplayObjects in reverse-placement order
380 /// - Cleanup key listeners
381 /// - Process all queued actions
382 /// - Remove unloaded DisplayObjects from the advanceable
383 /// DisplayObjects list.
384 /// - Run the GC collector
389 /// Get a unique number for unnamed instances.
390 size_t nextUnnamedInstance() {
391 return ++_unnamedInstance
;
394 /// Push a new DisplayObject listener for key events
395 void registerButton(Button
* listener
);
397 /// Remove a DisplayObject listener for key events
398 void removeButton(Button
* listener
);
400 /// Get the DisplayObject having focus
402 /// The DisplayObject having focus will receive mouse button
403 /// and key presses/releases.
405 /// @return the DisplayObject having focus or NULL of none.
407 DisplayObject
* getFocus();
409 /// Set the DisplayObject having focus
412 /// The DisplayObject to receive focus. NULL to kill focus.
413 /// @return true if the focus operation succeeded, false if the passed
414 /// DisplayObject cannot receive focus. setFocus(0) is a valid operation, so
415 /// returns true (always succeeds).
416 bool setFocus(DisplayObject
* to
);
418 DSOEXPORT
void add_invalidated_bounds(InvalidatedRanges
& ranges
,
421 /// Return the topmost active entity under the pointer
423 /// This method returns cached info, with cache updated
424 /// by notify_mouse_moved (and should be updated also
425 /// by movie advancement or actions execution maybe, not
426 /// currently implmented).
428 /// @return the topmost active entity under pointer or NULL if none.
429 DisplayObject
* getActiveEntityUnderPointer() const;
431 /// Return the topmost non-dragging entity under the pointer
433 /// This method triggers a displaylist scan
435 /// @return the topmost non-dragging entity under pointer or NULL if none
436 const DisplayObject
* getEntityUnderPointer() const;
438 /// Return the DisplayObject currently being dragged, if any
439 DisplayObject
* getDraggingCharacter() const;
441 bool testInvariant() const;
443 /// The possible values of Stage.displayState
446 DISPLAYSTATE_FULLSCREEN
449 /// The possibile values of Stage.scaleMode
457 /// The possible horizonal positions of the Stage
458 enum StageHorizontalAlign
{
464 /// The possible vertical position of the Stage
465 enum StageVerticalAlign
{
471 /// The possible elements of a Stage.alignMode.
479 /// The possibile values of AllowScriptAccess
480 enum AllowScriptAccessMode
{
482 SCRIPT_ACCESS_SAME_DOMAIN
,
486 /// Set the current display quality of the entire SWF.
487 void setQuality(Quality q
);
489 /// Get the current display quality.
490 Quality
getQuality() const { return _quality
; }
492 /// Sets movie_root's horizontal and vertical alignment to one
493 /// of the three possible positions for each dimension.
494 void setStageAlignment(short s
);
496 /// Sets the flag to allow interfacing with JavaScript in the browser.
497 /// This is disabled by default, but enabled for ExternalInterface.
498 void setAllowScriptAccess(AllowScriptAccessMode mode
);
500 /// Gets the current Access Mode for ExternalInterface.
501 AllowScriptAccessMode
getAllowScriptAccess();
503 typedef std::pair
<StageHorizontalAlign
, StageVerticalAlign
> StageAlign
;
505 /// Returns the current alignment of the stage (left/right/centre, top/
506 /// bottom/centre) as a std::pair
507 StageAlign
getStageAlignment() const;
509 /// Returns the current value of _showMenu which instructs the gui about
510 /// how much to display in the context menu
511 bool getShowMenuState() const;
513 /// Sets the value of _showMenu and calls the fscommand handler for the
515 void setShowMenuState(bool state
);
517 /// Sets the Stage object's align mode.
518 void setStageScaleMode(ScaleMode sm
);
520 /// Returns the Stage object's align mode.
521 ScaleMode
getStageScaleMode() const { return _scaleMode
; }
523 // The string representation of the current align mode.
524 std::string
getStageAlignMode() const;
526 /// Returns the Stage object's align mode.
527 DisplayState
getStageDisplayState() const { return _displayState
; }
529 // The string representation of the current align mode.
530 void setStageDisplayState(const DisplayState ds
);
532 /// Action priority levels
533 enum ActionPriorityLevel
{
534 /// Init actions, Init event handlers
536 /// Construct event handlers
538 /// Frame actions, load handlers, unload handlers
540 /// Last element used to easy computation of size...
544 /// A number of queues of code to execute
546 /// This is a ptr_deque because it needs no insertion in the middle but
547 /// frequent push_back and pop_front. We also have to traverse it, so
548 /// a queue is not usable.
549 typedef std::array
<boost::ptr_deque
<ExecutableCode
>, PRIORITY_SIZE
>
552 /// Push an executable code to the ActionQueue
553 void pushAction(std::unique_ptr
<ExecutableCode
> code
, size_t lvl
);
555 /// Push an executable code to the ActionQueue
556 void pushAction(const action_buffer
& buf
, DisplayObject
* target
);
558 /// Mark all reachable resources (for GC)
560 /// Resources reachable from movie_root are:
562 /// - All _level# movies (_movies)
563 /// - The original root movie (_rootMovie)
564 /// - Mouse entities (m_mouse_button_state)
565 /// - Timer targets (_intervalTimers)
566 /// - ExternalInterace callbacks (_externalCallbackMethods and
567 /// _externalCallbackInstances)
568 /// - Resources reachable by ActionQueue code (_actionQueue)
569 /// - Any DisplayObject being dragged
570 void markReachableResources() const;
573 /// Register a newly born advanceable DisplayObject to the
574 /// list of DisplayObjects to be advanced on next ::advance call.
576 /// The DisplayObject will only be advanced if not unloaded when
577 /// its turn comes. Characters are advanced in reverse-placement
578 /// order (first registered is advanced last)
580 void addLiveChar(MovieClip
* ch
)
582 // Don't register the object in the list twice
583 #if GNASH_PARANOIA_LEVEL > 1
584 assert(std::find(_liveChars
.begin(), _liveChars
.end(), ch
) ==
587 _liveChars
.push_front(ch
);
590 /// Reset stage to its initial state
593 /// Call this method for disabling run of actions
595 /// NOTE: this will only work for queued actions, not
596 /// for *every* action. Supposedly all actions should
597 /// be queued, but this is not really always the case.
598 /// Notable exceptions are:
599 /// - Actions in callFrame target frame
600 /// but only executed by execution of the callFrame opcode
601 /// - on{,Clip}{Initialize,Construct} event handlers
602 /// - User event handlers (mouse,keyboard)
604 void disableScripts();
606 /// Return true if scripts execution is disabled
607 bool scriptsDisabled() const { return _disableScripts
; };
609 /// Process action queues with higher priority then the priority
610 /// of the action queue currently being processed.
612 /// This is intended to be called at the end of any function call
613 /// and at the end of an action block.
615 /// TODO: be aware of infinite loops !
617 void flushHigherPriorityActionQueues();
619 DisplayObject
* findCharacterByTarget(const std::string
& tgtstr
) const;
621 /// Queue a request for loading a movie
623 /// This function constructs the URL and, if required, the postdata
624 /// from the arguments. The variables to send should *not* be appended
625 /// to @param urlstr before calling this function.
627 /// @param urlstr The url exactly as requested. This may already
628 /// contain a query string.
629 /// @param target Target for request.
630 /// @param data The variables data to send, URL encoded in
632 /// @param method The VariablesMethod to use for sending the data. If
633 /// MovieClip::METHOD_NONE, no data will be sent.
634 /// @param handler An object which will be signalled of load
635 /// events (onLoadStart, onLoadComplete, onLoadInit,
636 /// onLoadError). Can be null if caller doesn't care.
638 void loadMovie(const std::string
& url
, const std::string
& target
,
639 const std::string
& data
, MovieClip::VariablesMethod method
,
640 as_object
* handler
=nullptr)
642 _movieLoader
.loadMovie(url
, target
, data
, method
, handler
);
645 /// Send a request to the hosting application (e.g. browser).
647 /// This function constructs the URL and, if required, the postdata
648 /// from the arguments. The variables to send should *not* be appended
649 /// to @param urlstr before calling this function.
651 /// @param urlstr The url exactly as requested. This may already
652 /// contain a query string.
653 /// @param target Target for request.
654 /// @param data The variables data to send, URL encoded in
656 /// @param method The VariablesMethod to use for sending the data. If
657 /// MovieClip::METHOD_NONE, no data will be sent.
658 void getURL(const std::string
& urlstr
, const std::string
& target
,
659 const std::string
& data
, MovieClip::VariablesMethod method
);
662 key::code
lastKeyEvent() const {
663 return _lastKeyEvent
;
666 const Keys
& unreleasedKeys() const {
667 return _unreleasedKeys
;
670 /// Register an actionscript class for construction of a MovieClip
672 /// @param sprite The definition tag for the MovieClip to be placed on
674 /// @param class The ActionScript class to be used in construction.
675 void registerClass(const SWF::DefinitionTag
* sprite
, as_function
* cls
);
677 /// Get the actionscript class for constructing a MovieClip
679 /// @param sprite The definition tag for the MovieClip to be placed on
681 /// @return The class to be used, or 0 if no class is associated.
682 as_function
* getRegisteredClass(const SWF::DefinitionTag
* sprite
) const;
684 /// Set a filedescriptor to use for host application requests
685 /// (for browser communication mostly)
686 void setHostFD(int fd
) {
691 /// Set a filedescriptor to use for host application requests
692 /// (for browser communication mostly)
693 void setControlFD(int fd
) {
697 /// Get the filedescriptor to use for host application requests
698 /// (for browser communication mostly)
700 /// @return -1 if no filedescriptor is provided by host app.
701 int getHostFD() const {
705 int getControlFD() const {
709 /// ActionScript embedded in a movie can use the built-in
710 /// fscommand() function to send data back to the host
711 /// application. If you are interested in this data, register
712 /// a handler, which will be called when the embedded scripts
713 /// call fscommand().
715 /// The handler gets the MovieClip* that the script is
716 /// embedded in, and the two string arguments passed by the
717 /// script to fscommand().
718 DSOEXPORT
void registerFSCommandCallback(FsCallback
* handler
) {
719 _fsCommandHandler
= handler
;
722 /// Call this to notify FS commands
723 DSOEXPORT
void handleFsCommand(const std::string
& cmd
,
724 const std::string
& arg
) const;
726 /// A callback to the GUI (or whatever is listening) for sending
727 /// events and receiving replies. Used for ActionScript interface
728 /// with the gui (Mouse visibility, Stage alignment etc and System
729 /// information, for instance).
731 /// See callInterface method
732 DSOEXPORT
void registerEventCallback(HostInterface
* handler
) {
733 _interfaceHandler
= handler
;
736 /// Call the hosting application without expecting a reply.
738 /// @param e The message to send to the interface.
739 void callInterface(const HostInterface::Message
& e
) const;
741 /// Call the hosting application, ensuring a return of the requested type.
743 /// If the return type is other than the requested type, this represents
744 /// a bug in the hosting application. An error is logged and the default
745 /// constructed type T is returned. This may cause unexpected
746 /// ActionScript behaviour, but is otherwise safe.
748 /// @tparam T The return type expected.
749 /// @param e The message to send to the interface.
750 template<typename T
> T
callInterface(const HostInterface::Message
& e
) const;
752 /// Called from the ScriptLimits tag parser to set the
753 /// global script limits. It is expected behaviour that
754 /// each new loaded movie should override this.
755 /// Can be overridden from gnashrc.
757 /// @param recursion the maximum number of recursions when
759 /// The default value for this (i.e. when no
760 /// ScriptLimits tag is present) is documented to be
761 /// 256, but this may change and appears not to be
762 /// crucial for (backward) compatibility.
763 /// @param timeout the timeout in seconds for script execution.
764 /// The default value for this (i.e. when no
765 /// ScriptLimits tag is present) is documented to be
766 /// 15 to 20 seconds, depending on platform.
767 void setScriptLimits(std::uint16_t recursion
, std::uint16_t timeout
);
769 /// Get the current global recursion limit for this movie: it can
770 /// be changed by loaded movies.
771 std::uint16_t getRecursionLimit() const {
772 return _recursionLimit
;
775 /// Get the current global script timeout limit for this movie: it
776 /// can be changed by loaded movies.
777 std::uint16_t getTimeoutLimit() const
779 return _timeoutLimit
;
783 typedef tree
<std::pair
<std::string
, std::string
> > InfoTree
;
784 void getMovieInfo(InfoTree
& tr
, InfoTree::iterator it
);
785 void getCharacterTree(InfoTree
& tr
, InfoTree::iterator it
);
788 const RunResources
& runResources() const { return _runResources
; }
790 typedef std::map
<std::string
, as_object
*> ExternalCallbackMethods
;
791 typedef std::map
<std::string
, as_object
*> ExternalCallbackInstances
;
792 ExternalCallbackMethods _externalCallbackMethods
;
793 ExternalCallbackInstances _externalCallbackInstances
;
795 /// Add an ExternalInterface callback object with an associated name.
797 /// @param name Callback name, exposed to host container.
798 /// @param callback ActionScript function to be invoked if the callback
800 /// @param instance ActionScript Object to be used as "this" instance
801 /// inside the callback. ActionScript null value is
803 void addExternalCallback(const std::string
& name
, as_object
* callback
,
804 as_object
* instance
);
806 bool processInvoke(ExternalInterface::invoke_t
*);
808 std::string
callExternalCallback(const std::string
&name
,
809 const std::vector
<as_value
>& args
);
811 std::string
callExternalJavascript(const std::string
&name
,
812 const std::vector
<as_value
>& args
);
814 /// Removes a queued constructor from the execution queue
816 /// This is used to prevent construction of targets that are placed and
817 /// then removed in skipped frames. Callers are responsible for determining
818 /// whether it should be removed, for instance by checking for an
819 /// onUnload handler.
820 void removeQueuedConstructor(MovieClip
* target
);
826 /// Ask the host interface a question.
828 /// @param what The question to pose.
829 /// @return The answer (true for yes, false for no).
830 bool queryInterface(const std::string
& what
) const;
832 /// Set the current stream block for the driving streaming sound.
834 /// The frame rate will be changed so that it advances only when the
835 /// block for a particular frame is reached. Only one sound can drive the
836 /// frame: the first one to be registered.
838 /// @param id The id of the stream; if another stream is already
839 /// driving the frame rate, nothing happens.
840 /// @param block The block of sound currently being played. The current
841 /// frame will be advanced or delayed until the frame
842 /// corresponding to this block is reached.
843 void setStreamBlock(int id
, int block
);
845 /// Notify the stage that a sound stream has stopped.
847 /// If it's the one driving the frame rate, the frame rate will return to
850 /// @param id The id of the streaming sound.
851 void stopStream(int id
);
855 /// Set the root movie, replacing the current one if any.
857 /// This is needed for the cases in which the top-level movie
858 /// is replaced by another movie by effect of a loadMovie call
861 /// TODO: inspect what happens about VM version
862 /// (should the *new* movie drive VM operations?
865 /// Make sure to call this method before using the movie_root,
866 /// as most operations are delegated to the associated/wrapped
869 /// Note that the display viewport will be updated to match
870 /// the size of given movie.
872 /// A call to this method is equivalent to a call to setLevel(0, movie).
875 /// The Movie to wrap.
876 /// Must have a depth of 0.
878 void setRootMovie(Movie
* movie
);
880 /// Handle mouse events.
881 bool notify_mouse_listeners(const event_id
& event
);
883 /// This function should return TRUE iff any action triggered
884 /// by the event requires redraw, see \ref events_handling for
886 bool fire_mouse_event();
888 /// Take care of dragging, if needed
891 /// Execute expired timers
892 void executeAdvanceCallbacks();
894 /// Execute expired timers
895 void executeTimers();
897 /// Cleanup references to unloaded DisplayObjects and run the GC.
898 void cleanupAndCollect();
901 /// Return the topmost entity covering the given point
902 /// and enabled to receive mouse events.
904 /// Return NULL if no "active" entity is found under the pointer.
906 /// Coordinates of the point are given in world coordinate space.
910 /// X ordinate of the pointer, in world coordinate space (twips)
913 /// Y ordinate of the pointer, in world coordiante space (twips).
915 InteractiveObject
* getTopmostMouseEntity(std::int32_t x
,
916 std::int32_t y
) const;
918 /// Delete DisplayObjects removed from the stage
919 /// from the display lists
920 void cleanupDisplayList();
922 /// Advance all non-unloaded live chars
923 void advanceLiveChars();
925 /// Boundaries of the Stage are always world boundaries
926 /// and are only invalidated by changes in the background
928 void setInvalidated() { _invalidated
= true; }
930 /// Every ::display call clears the invalidated flag
932 /// See setInvalidated();
934 void clearInvalidated() { _invalidated
= false; }
936 /// An invalidated stage will trigger complete redraw
938 /// So, this method should return true everytime a complete
939 /// redraw is needed. This is typically only needed when
940 /// the background changes.
942 /// See setInvalidated() and clearInvalidated().
944 bool isInvalidated() { return _invalidated
; }
946 /// Return the priority level of first action queue containing actions.
948 /// Scanned in proprity order (lower first)
950 size_t minPopulatedPriorityQueue() const;
952 /// Process all actions in the the given queue, till more actions
953 /// are found in lower levels, in which case we have an earlier
955 size_t processActionQueue(size_t lvl
);
957 bool processingActions() const {
958 return (_processingActionLevel
< PRIORITY_SIZE
);
961 const DisplayObject
* findDropTarget(std::int32_t x
, std::int32_t y
,
962 DisplayObject
* dragging
) const;
964 void handleActionLimitHit(const std::string
& ref
);
966 typedef std::forward_list
<Button
*> ButtonListeners
;
967 ButtonListeners _buttonListeners
;
971 const RunResources
& _runResources
;
973 /// This initializes a SharedObjectLibrary, which requires
974 /// _baseURL, so that must be initialized first.
977 /// Registered Interface command handler, if any
978 HostInterface
* _interfaceHandler
;
980 /// Registered FsCommand handler, if any
981 FsCallback
* _fsCommandHandler
;
983 /// A list of AdvanceableCharacters
985 /// This is a list (not a vector) as we want to allow
986 /// ::advance of each element to insert new DisplayObjects before
987 /// the start w/out invalidating iterators scanning the
988 /// list forward for proper movie advancement
989 typedef std::forward_list
<MovieClip
*> LiveChars
;
991 /// The list of advanceable DisplayObject, in placement order
992 LiveChars _liveChars
;
994 ActionQueue _actionQueue
;
996 /// Process all actions in the queue
997 void processActionQueue();
999 /// Width and height of viewport, in pixels
1001 size_t _stageHeight
;
1003 rgba m_background_color
;
1004 bool m_background_color_set
;
1006 std::int32_t _mouseX
;
1007 std::int32_t _mouseY
;
1009 MouseButtonState _mouseButtonState
;
1011 /// Objects requesting a callback on every movie_root::advance()
1012 typedef std::set
<ActiveRelay
*> ObjectCallbacks
;
1013 ObjectCallbacks _objectCallbacks
;
1015 LoadCallbacks _loadCallbacks
;
1017 typedef std::map
<std::uint32_t, std::unique_ptr
<Timer
>> TimerMap
;
1019 TimerMap _intervalTimers
;
1021 size_t _lastTimerId
;
1023 /// bit-array for recording the unreleased keys
1024 Keys _unreleasedKeys
;
1026 key::code _lastKeyEvent
;
1028 /// The DisplayObject currently holding focus, or 0 if no focus.
1029 DisplayObject
* _currentFocus
;
1031 /// @todo fold this into m_mouse_button_state?
1032 boost::optional
<DragState
> _dragState
;
1034 typedef std::map
<int, MovieClip
*> Levels
;
1036 /// The movie instance wrapped by this movie_root
1038 /// We keep a pointer to the base MovieClip class
1039 /// to avoid having to replicate all of the base class
1040 /// interface to the Movie class definition
1043 typedef std::map
<const SWF::DefinitionTag
*, as_function
*> RegisteredClasses
;
1044 RegisteredClasses _registeredClasses
;
1046 /// The root movie. This is initially the same as getLevel(0) but might
1047 /// change during the run. It will be used to setup and retrive initial
1051 /// See setInvalidated
1054 /// This is set to true if execution of scripts
1055 /// aborted due to action limit set or whatever else
1056 bool _disableScripts
;
1057 int _processingActionLevel
;
1059 /// filedescriptor to write to for host application requests
1065 /// The display quality of the entire movie.
1067 /// This is here, not just in the Renderer, so that AS compatibility
1068 /// does not rely on the presence of a renderer.
1071 /// The alignment of the Stage
1072 std::bitset
<4u> _alignMode
;
1074 AllowScriptAccessMode _allowScriptAccess
;
1076 /// Whether to show the menu or not.
1079 /// The current scaling mode of the Stage.
1080 ScaleMode _scaleMode
;
1082 /// The current state of the Stage (fullscreen or not).
1083 DisplayState _displayState
;
1085 // Maximum number of recursions set in the ScriptLimits tag.
1086 std::uint16_t _recursionLimit
;
1088 // Timeout in seconds for script execution, set in the ScriptLimits tag.
1089 std::uint16_t _timeoutLimit
;
1091 // delay between movie advancement, in milliseconds
1092 size_t _movieAdvancementDelay
;
1094 // time of last movie advancement, in milliseconds
1095 size_t _lastMovieAdvancement
;
1097 /// The number of the last unnamed instance, used to name instances.
1098 size_t _unnamedInstance
;
1100 MovieLoader _movieLoader
;
1102 struct SoundStream
{
1103 SoundStream(int i
, int b
) : id(i
), block(b
) {}
1108 boost::optional
<SoundStream
> _timelineSound
;
1111 /// Return true if the given string can be interpreted as a _level name
1114 /// The target string.
1115 /// Will be considered case-insensitive if VM version is < 7.
1118 /// Output parameter, will be set to the level number, if true is
1120 bool isLevelTarget(int version
, const std::string
& name
, unsigned int& levelno
);
1122 DSOEXPORT
short stringToStageAlign(const std::string
& s
);
1124 template<typename T
>
1126 movie_root::callInterface(const HostInterface::Message
& e
) const
1128 if (!_interfaceHandler
) {
1129 log_error("Hosting application registered no callback for "
1130 "messages, can't call %s(%s)");
1135 return boost::any_cast
<T
>(_interfaceHandler
->call(e
));
1137 catch (const boost::bad_any_cast
&) {
1138 log_error(_("Unexpected type from host interface when requesting "
1144 } // namespace gnash
1146 #endif // GNASH_MOVIE_ROOT_H
1150 // indent-tabs-mode: nil