2 // Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010,
3 // 2011 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
23 #include "gnashconfig.h"
26 #include <boost/intrusive_ptr.hpp>
33 #include "snappingrange.h" // for InvalidatedRanges
35 #include "VirtualClock.h"
36 #include "SystemClock.h"
37 #include "GnashEnums.h"
38 #include "movie_root.h"
41 #include "tree.hh" // for tree
44 // Define this to enable fps debugging without touching
46 //#define GNASH_FPS_DEBUG
48 /// Define this to disable region updates debugging altogether. If undefined,
49 /// debugging will be a runtime option. The flag and flag-setting functions
50 /// will not be disabled (too ugly).
52 /// This should go in gnashconfig.h
54 /// This has the side effect that all frames will be re-rendered completely
55 /// but in contrast to FORCE_REDRAW it won't re-render when no motion
56 /// has been detected in the movie (for example when the movie is stopped).
58 //#define DISABLE_REGION_UPDATES_DEBUGGING 1
61 /// Define this to support keyboard-based pointer movements
62 #define ENABLE_KEYBOARD_MOUSE_MOVEMENTS 1
64 // Forward declarations
70 class movie_definition
;
75 template <typename Signature
> class function
;
80 /// Enumerates mouse cursor types.
81 enum gnash_cursor_type
{
87 /// Parent class from which all GUI implementations will depend.
95 /// Initialise the gui and the associated renderer.
97 /// @param argc The commandline argument count.
98 /// @param argv The commandline arguments.
99 /// @return True on success; false on failure.
100 virtual bool init(int argc
, char **argv
[]) = 0;
102 /// Set main loop delay in milliseconds.
103 virtual void setInterval(unsigned int interval
) {
104 _interval
= interval
;
107 /// Return the clock provided by this Gui.
109 /// The Gui clock will be paused when the gui is put
110 /// in pause mode and resumed when gui playback is resumed.
112 virtual VirtualClock
& getClock() { return _virtualClock
; }
114 /// Set the time in milliseconds after which the programme should exit.
115 virtual void setTimeout(unsigned int timeout
) = 0;
117 void setScreenShotter(std::unique_ptr
<ScreenShotter
> ss
);
120 /// Create and display our window.
122 /// @param title The window title.
123 /// @param width The desired window width in pixels.
124 /// @param height The desired window height in pixels.
125 /// @param xPosition The desired window X position from the top left corner.
126 /// @param yPosition The desired window Y position from the top left corner.
127 virtual bool createWindow(const char* title
, int width
, int height
,
128 int xPosition
= 0, int yPosition
= 0) = 0;
130 virtual void resizeWindow(int width
, int height
);
132 /// Start main rendering loop.
133 virtual bool run() = 0;
135 /// Always called on exit.
137 /// Handles any common functions, then calls virtual quitUI().
140 /// Render the current buffer.
141 /// For OpenGL, this means that the front and back buffers are swapped.
142 virtual void renderBuffer() = 0;
144 /// Gives the GUI a *hint* which region of the stage should be redrawn.
146 /// There is *no* restriction what the GUI might do with these coordinates.
147 /// Normally the GUI forwards the information to the renderer so that
148 /// it avoids rendering regions that did not change anyway. The GUI can
149 /// also alter the bounds before passing them to the renderer and it's
150 /// absolutely legal for the GUI to simply ignore the call.
152 /// Coordinates are in TWIPS!
154 /// Note this information is given to the GUI and not directly to the
155 /// renderer because both of them need to support this feature for
156 /// correct results. It is up to the GUI to forward this information to
159 // does not need to be implemented (optional feature),
160 // but still needs to be available.
162 virtual void setInvalidatedRegion(const SWFRect
& bounds
);
163 virtual void setInvalidatedRegions(const InvalidatedRanges
& ranges
);
165 // Called right before rendering anything (after setInvalidatedRegion).
167 virtual void beforeRendering() { /* nop */ };
169 // Should return TRUE when the GUI/Renderer combination supports multiple
170 // invalidated bounds regions.
171 virtual bool want_multiple_regions() { return false; }
173 /// Asks the GUI handler if the next frame should be redrawn completely.
175 /// For example, when the contents of the player window have been destroyed,
176 /// then want_redraw() should return true so that setInvalidatedRegion() is
177 /// called with the coordinates of the complete screen.
178 virtual bool want_redraw();
180 /// Sets the current mouse cursor for the Gui window.
181 virtual void setCursor(gnash_cursor_type newcursor
);
183 virtual void setClipboard(const std::string
& copy
);
185 // Information for System.capabilities to be reimplemented in
187 virtual double getPixelAspectRatio() const { return 0; }
189 virtual std::pair
<int, int> screenResolution() const {
190 return std::make_pair(0, 0);
193 virtual double getScreenDPI() const { return 0; }
195 /// Get the screen color type.
197 /// The choice is between "color" and something designating
198 /// monochrome (not sure what). If this isn't implemented in the
199 /// gui we return "color".
200 virtual std::string
getScreenColor() const {
204 /// @return Whether or not the movie should be looped indefinitely.
205 bool loops() const { return _loop
; }
207 /// @return Whether the movie is running fullscreen or not.
208 bool isFullscreen() const { return _fullscreen
; }
210 /// Mouse notification callback to be called when the mouse is moved.
212 /// @param x The mouse coordinate X component in user/window
213 /// coordinate space (pixels).
214 /// @param y The mouse coordinate Y component in user/window
215 /// coordinate space (pixels).
216 void notifyMouseMove(int x
, int y
);
218 /// Mouse notification callback to be called when the mouse is clicked.
220 /// @param mouse_pressed Determines whether the mouse button is being
221 /// pressed (true) or being released (false)
222 void notifyMouseClick(bool mouse_pressed
);
224 /// Send a mouse wheel event to the stage.
226 /// @param delta A number expressing the extent of the wheel scroll.
227 void notifyMouseWheel(int delta
);
229 /// Key event notification to be called when a key is pressed or depressed
231 /// @param k The key code.
233 /// Modifier key identifiers from gnash::key::modifier ORed together
235 /// Determines whether the key is being pressed (true)
236 /// or being released (false)
238 void notify_key_event(gnash::key::code k
, int modifier
, bool pressed
);
240 /// Resize the client area view and the window accordingly.
242 /// @param width The desired width in pixels.
243 /// @param height The desired height in pixels.
244 void resize_view(int width
, int height
);
246 /// Update stage SWFMatrix accordingly to window size and flash Stage
247 /// configuration (scaleMode, alignment)
249 /// This method should be called from the core lib when Stage configuration
250 /// change or is called by resize_view.
252 void updateStageMatrix();
255 /// Give movie an heart-beat.
257 /// This is to take place after the
258 /// interval specified in the call to setInterval().
260 /// Wheter or not this beat advanced the movie to the next frame
261 /// depends on elapsed time since last advancement.
263 /// @return true if this beat resulted in actual frame advancement.
265 bool advanceMovie(bool doDisplay
= true);
267 /// Convenience static wrapper around advanceMovie for callbacks happiness.
269 /// NOTE: this function always return TRUE, for historical reasons.
270 /// TODO: bring code up-to-date to drop this legacy return code..
272 static bool advance_movie(Gui
* gui
) {
277 /// Force immediate redraw
281 /// Attempt to run in a fullscreen window both for plugin and
282 /// standalone player.
284 /// Use isFullscreen() to see if gnash thinks
285 /// it's running in fullscreen or not. The switch to fullscreen may
286 /// fail if, for instance, the window manager refuses to allow it, but
287 /// the flag will be set anyway.
288 virtual void setFullscreen();
290 /// Return from fullscreen to normal mode.
292 virtual void unsetFullscreen();
294 /// Hide the menu bar when using standalone player
296 virtual void hideMenu();
298 /// Sets whether the gui should show the system mouse pointer
300 /// @param show true if the mouse should be shown.
301 /// @return true if the state changed.
302 virtual bool showMouse(bool show
);
304 /// Sets whether the menus should be shown (for fscommand)
306 /// @param show true if the menu bar should be shown.
307 virtual void showMenu(bool show
);
309 /// Sets whether scaling should be allowed (for fscommand)
311 /// @param allow true if stage scaling should be allowed
312 virtual void allowScale(bool allow
);
314 // Toggle between fullscreen and normal mode
315 void toggleFullscreen();
317 /// Put the application in "stop" mode
319 /// When in stop mode the application won't be advanced.
323 /// Put the application in "play" mode
325 /// When in play mode the application will be advanced as usual.
329 /// Toggle between "stop" and "play" mode
331 /// See stop() and play()
337 /// This function will create an instance of the registered top-level
338 /// movie definition, set variables into it and place it to the stage.
342 /// See stop(), play() and pause()
343 bool isStopped() const { return _stopped
; }
345 /// Whether gnash is is running as a plugin
346 bool isPlugin() const { return ((_xid
)); }
348 /// Take a screenshot now!
349 void takeScreenShot();
351 /// Set the maximum number of frame advances before Gnash exits.
352 void setMaxAdvances(unsigned long ul
) { if (ul
) _maxAdvances
= ul
; }
354 void showUpdatedRegions(bool x
) { _showUpdatedRegions
= x
; }
355 bool showUpdatedRegions() const { return _showUpdatedRegions
; }
357 /// Instruct the core to restart the movie and
358 /// set state to play(). This does not change pause
362 /// Set rendering quality, if not locked by RC file..
363 void setQuality(Quality q
);
365 /// Get current rendering quality
366 Quality
getQuality() const;
368 /// Toggle sound state between muted and unmuted. If
369 /// there is no active sound handler this does nothing.
372 #ifdef GNASH_FPS_DEBUG
373 /// Set the interval between FPS debugging prints
375 /// See fpsCounterTick()
377 void setFpsTimerInterval(float interval
)
379 assert(interval
>= 0.0);
380 fps_timer_interval
= interval
;
382 #endif // def GNASH_FPS_DEBUG
386 /// Return a tree containing information about the movie playing.
387 std::unique_ptr
<movie_root::InfoTree
> getMovieInfo() const;
390 typedef std::map
<std::string
, std::string
> VariableMap
;
392 /// Add variables to set into instances of the top-level movie definition
393 void addFlashVars(VariableMap
& vars
);
395 /// Set the definition of top-level movie
396 void setMovieDefinition(movie_definition
* md
);
398 /// Set the stage to advance/display
399 void setStage(movie_root
* stage
);
401 /// Set the name of a file to dump audio to
402 void setAudioDump(const std::string
& fname
) {
406 /// The root movie, or "Stage"
407 movie_root
* getStage() { return _stage
; };
409 /// Handle error message from the core
411 /// @param msg The error message recieved
413 virtual void error(const std::string
& /*msg*/) {}
415 /// Prompt user with a question she can answer with yes/no
418 /// The question to ask user
421 /// true for YES, false for NO
423 /// The default implementation always returns true.
425 virtual bool yesno(const std::string
& question
);
427 /// Width of a window pixel, in stage pseudopixel units.
428 float getXScale() const { return _xscale
; };
430 /// Height of a window pixel, in stage pseudopixel units.
431 float getYScale() const { return _yscale
; };
433 /// Height of a window pixel, in stage pseudopixel units.
434 float getFPS() const { return (_movieDef
) ? _movieDef
->get_frame_rate() : 0;
439 /// Default constructor. Initialises members to safe defaults.
440 Gui(RunResources
& r
);
443 * Expanded constructor for more control over member values.
445 * @param xid The X11 Window ID to attach to. If this is argument is zero,
446 * a new window is created.
448 * @param scale The scale used to resize the window size, which has been
449 * established by extracting information from the SWF file.
451 * @param loop Defines whether or not the movie should be played once or
452 * looped indefinitely.
454 * @param depth Colour depth to be used in the client area of our window.
456 Gui(unsigned long xid
, float scale
, bool loop
, RunResources
& r
);
458 /// End main rendering loop calling GUI-specific exit functions.
460 /// Do not call this directly. Call quit() instead.
462 /// The default implementation calls exit(EXIT_SUCCESS), which isn't nice.
463 /// Please implement the proper main loop quitter in the subclasses.
464 virtual void quitUI() {
465 std::exit(EXIT_SUCCESS
);
468 /// Watch a file descriptor.
470 /// An implementing Gui should monitor the file descriptor in its main
471 /// loop. When the file descriptor is triggered, the implementation should
472 /// call callCallback().
474 /// @param fd The file descriptor to be watched
475 virtual bool watchFD(int /* fd */)
477 log_unimpl("This GUI does not implement FD watching.");
482 /// Determines if playback should restart after the movie ends.
485 /// The X Window ID to attach to. If zero, we create a new window.
488 // This would be 0,0,_width,_height, so maybe
489 // we should not duplicate the info with those
490 // explicit values too..
491 geometry::Range2d
<int> _validbounds
;
493 /// Desired window width.
496 /// Desired window height.
499 /// Per-run resources
500 RunResources
& _runResources
;
502 /// Main loop interval: the time between successive advance_movie calls.
503 unsigned int _interval
;
505 /// The handler which is called to update the client area of our window.
506 std::shared_ptr
<Renderer
> _renderer
;
508 /// Signals that the next frame must be re-rendered completely because the
509 /// window size did change.
512 // True if Gnash is running in fullscreen
515 // True if mouse pointer is showing
518 // Maximum number of advances before exit; 0 for no limit.
519 unsigned long _maxAdvances
;
521 /// Counter to keep track of frame advances
522 unsigned long _advances
;
524 /// Name of a file to dump audio to
525 std::string _audioDump
;
527 /// Called by Gui::stop(). This can be used by GUIs to implement pause
528 /// widgets (so that resuming a stopped animation is more user-friendly)
529 virtual void stopHook() {}
531 /// Called by Gui::play().
532 virtual void playHook() {}
534 /// Determines whether the Gui is visible (not obscured).
535 virtual bool visible() { return true; }
540 std::map
<int /* fd */, std::function
<void ()> > _fd_callbacks
;
542 /// Width of a window pixel, in stage pseudopixel units.
545 /// Height of a window pixel, in stage pseudopixel units.
548 /// Window pixel X offset of stage origin
549 std::int32_t _xoffset
;
551 /// Window pixel Y offset of stage origin
552 std::int32_t _yoffset
;
554 bool display(movie_root
* m
);
556 #ifdef GNASH_FPS_DEBUG
557 unsigned int fps_counter
;
559 float fps_rate_min
, fps_rate_max
;
561 // Number of calls to fpsCounterTick, which is also
562 // the number of calls to movie_advance()
563 unsigned int fps_counter_total
;
565 std::uint64_t fps_timer
, fps_start_timer
;
567 /// The time, in seconds, between prints (which also resets the fps counter).
569 /// interval must be >= 0
571 float fps_timer_interval
;
573 /// Number of frames rendering of which was dropped
574 unsigned int frames_dropped
;
577 /// Should be called on every frame advance (including inter-frames caused
578 /// by mouse events).
580 /// Based on fps-timer_interval. See setFpsTimerInterval.
582 void fpsCounterTick();
584 #endif // def GNASH_FPS_DEBUG
586 VariableMap _flashVars
;
588 boost::intrusive_ptr
<movie_definition
> _movieDef
;
590 /// The root movie, or "Stage"
593 /// True if the application has been put into "stop" mode
596 /// True if the application didn't start yet
599 /// If true, updated regions (invalidated ranges) are visibly outlined.
600 bool _showUpdatedRegions
;
602 SystemClock _systemClock
;
603 InterruptableVirtualClock _virtualClock
;
605 /// Checked on each advance for screenshot activity if it exists.
606 std::unique_ptr
<ScreenShotter
> _screenShotter
;
608 #ifdef ENABLE_KEYBOARD_MOUSE_MOVEMENTS
611 bool _keyboardMouseMovements
;
612 int _keyboardMouseMovementsStep
;
613 #endif // ENABLE_KEYBOARD_MOUSE_MOVEMENTS
616 /// Named constructors
618 std::unique_ptr
<Gui
> createFBGui(unsigned long xid
, float scale
, bool loop
, RunResources
& r
);
620 std::unique_ptr
<Gui
> createGTKGui(unsigned long xid
, float scale
, bool loop
, RunResources
& r
);
621 std::unique_ptr
<Gui
> createKDEGui(unsigned long xid
, float scale
, bool loop
, RunResources
& r
);
622 std::unique_ptr
<Gui
> createQt4Gui(unsigned long xid
, float scale
, bool loop
, RunResources
& r
);
623 std::unique_ptr
<Gui
> createSDLGui(unsigned long xid
, float scale
, bool loop
, RunResources
& r
);
624 std::unique_ptr
<Gui
> createFLTKGui(unsigned long xid
, float scale
, bool loop
, RunResources
& r
);
625 std::unique_ptr
<Gui
> createAQUAGui(unsigned long xid
, float scale
, bool loop
, RunResources
& r
);
626 std::unique_ptr
<Gui
> createRISCOSGui(unsigned long xid
, float scale
, bool loop
, RunResources
& r
);
627 std::unique_ptr
<Gui
> createAOS4Gui(unsigned long xid
, float scale
, bool loop
, RunResources
& r
);
628 std::unique_ptr
<Gui
> createHaikuGui(unsigned long xid
, float scale
, bool loop
, RunResources
& r
);
629 std::unique_ptr
<Gui
> createDumpGui(unsigned long xid
, float scale
, bool loop
, RunResources
& r
);
632 } // end of gnash namespace
639 // indent-tabs-mode: nil