1 // 2 // Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 3 // 2011 Free Software Foundation, Inc 4 // 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. 9 // 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. 14 // 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 18 19 #ifndef GNASH_GUI_H 20 #define GNASH_GUI_H 21 22 #ifdef HAVE_CONFIG_H 23 #include "gnashconfig.h" 24 #endif 25 26 #include <boost/intrusive_ptr.hpp> 27 #include <memory> 28 #include <string> 29 #include <map> 30 #include <utility> 31 #include <functional> 32 33 #include "snappingrange.h" // for InvalidatedRanges 34 #include "GnashKey.h" 35 #include "VirtualClock.h" 36 #include "SystemClock.h" 37 #include "GnashEnums.h" 38 #include "movie_root.h" 39 40 #ifdef USE_SWFTREE 41 #include "tree.hh" // for tree 42 #endif 43 44 // Define this to enable fps debugging without touching 45 // gnashconfig.h 46 //#define GNASH_FPS_DEBUG 47 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). 51 /// 52 /// This should go in gnashconfig.h 53 /// 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). 57 /// 58 //#define DISABLE_REGION_UPDATES_DEBUGGING 1 59 60 61 /// Define this to support keyboard-based pointer movements 62 #define ENABLE_KEYBOARD_MOUSE_MOVEMENTS 1 63 64 // Forward declarations 65 namespace gnash { 66 class SWFRect; 67 class ScreenShotter; 68 class RunResources; 69 class movie_root; 70 class movie_definition; 71 class Renderer; 72 class SWFRect; 73 } 74 namespace boost { 75 template <typename Signature> class function; 76 } 77 78 namespace gnash { 79 80 /// Enumerates mouse cursor types. 81 enum gnash_cursor_type { 82 CURSOR_HAND, 83 CURSOR_NORMAL, 84 CURSOR_INPUT 85 }; 86 87 /// Parent class from which all GUI implementations will depend. 88 class Gui { 89 90 public: 91 92 virtual ~Gui(); 93 94 /// \brief/ 95 /// Initialise the gui and the associated renderer. 96 /// 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; 101 102 /// Set main loop delay in milliseconds. setInterval(unsigned int interval)103 virtual void setInterval(unsigned int interval) { 104 _interval = interval; 105 } 106 107 /// Return the clock provided by this Gui. 108 // 109 /// The Gui clock will be paused when the gui is put 110 /// in pause mode and resumed when gui playback is resumed. 111 /// getClock()112 virtual VirtualClock& getClock() { return _virtualClock; } 113 114 /// Set the time in milliseconds after which the programme should exit. 115 virtual void setTimeout(unsigned int timeout) = 0; 116 117 void setScreenShotter(std::unique_ptr<ScreenShotter> ss); 118 119 /// \brief 120 /// Create and display our window. 121 /// 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; 129 130 virtual void resizeWindow(int width, int height); 131 132 /// Start main rendering loop. 133 virtual bool run() = 0; 134 135 /// Always called on exit. 136 // 137 /// Handles any common functions, then calls virtual quitUI(). 138 void quit(); 139 140 /// Render the current buffer. 141 /// For OpenGL, this means that the front and back buffers are swapped. 142 virtual void renderBuffer() = 0; 143 144 /// Gives the GUI a *hint* which region of the stage should be redrawn. 145 // 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. 151 /// 152 /// Coordinates are in TWIPS! 153 /// 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 157 /// the renderer. 158 /// 159 // does not need to be implemented (optional feature), 160 // but still needs to be available. 161 // 162 virtual void setInvalidatedRegion(const SWFRect& bounds); 163 virtual void setInvalidatedRegions(const InvalidatedRanges& ranges); 164 165 // Called right before rendering anything (after setInvalidatedRegion). 166 // Used by GTK-AGG. beforeRendering()167 virtual void beforeRendering() { /* nop */ }; 168 169 // Should return TRUE when the GUI/Renderer combination supports multiple 170 // invalidated bounds regions. want_multiple_regions()171 virtual bool want_multiple_regions() { return false; } 172 173 /// Asks the GUI handler if the next frame should be redrawn completely. 174 // 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(); 179 180 /// Sets the current mouse cursor for the Gui window. 181 virtual void setCursor(gnash_cursor_type newcursor); 182 183 virtual void setClipboard(const std::string& copy); 184 185 // Information for System.capabilities to be reimplemented in 186 // each gui. getPixelAspectRatio()187 virtual double getPixelAspectRatio() const { return 0; } 188 screenResolution()189 virtual std::pair<int, int> screenResolution() const { 190 return std::make_pair(0, 0); 191 } 192 getScreenDPI()193 virtual double getScreenDPI() const { return 0; } 194 195 /// Get the screen color type. 196 // 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". getScreenColor()200 virtual std::string getScreenColor() const { 201 return "color"; 202 } 203 204 /// @return Whether or not the movie should be looped indefinitely. loops()205 bool loops() const { return _loop; } 206 207 /// @return Whether the movie is running fullscreen or not. isFullscreen()208 bool isFullscreen() const { return _fullscreen; } 209 210 /// Mouse notification callback to be called when the mouse is moved. 211 // 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); 217 218 /// Mouse notification callback to be called when the mouse is clicked. 219 // 220 /// @param mouse_pressed Determines whether the mouse button is being 221 /// pressed (true) or being released (false) 222 void notifyMouseClick(bool mouse_pressed); 223 224 /// Send a mouse wheel event to the stage. 225 // 226 /// @param delta A number expressing the extent of the wheel scroll. 227 void notifyMouseWheel(int delta); 228 229 /// Key event notification to be called when a key is pressed or depressed 230 // 231 /// @param k The key code. 232 /// @param modifier 233 /// Modifier key identifiers from gnash::key::modifier ORed together 234 /// @param pressed 235 /// Determines whether the key is being pressed (true) 236 /// or being released (false) 237 /// 238 void notify_key_event(gnash::key::code k, int modifier, bool pressed); 239 240 /// Resize the client area view and the window accordingly. 241 // 242 /// @param width The desired width in pixels. 243 /// @param height The desired height in pixels. 244 void resize_view(int width, int height); 245 246 /// Update stage SWFMatrix accordingly to window size and flash Stage 247 /// configuration (scaleMode, alignment) 248 // 249 /// This method should be called from the core lib when Stage configuration 250 /// change or is called by resize_view. 251 /// 252 void updateStageMatrix(); 253 254 /// \brief 255 /// Give movie an heart-beat. 256 // 257 /// This is to take place after the 258 /// interval specified in the call to setInterval(). 259 /// 260 /// Wheter or not this beat advanced the movie to the next frame 261 /// depends on elapsed time since last advancement. 262 /// 263 /// @return true if this beat resulted in actual frame advancement. 264 /// 265 bool advanceMovie(bool doDisplay = true); 266 267 /// Convenience static wrapper around advanceMovie for callbacks happiness. 268 // 269 /// NOTE: this function always return TRUE, for historical reasons. 270 /// TODO: bring code up-to-date to drop this legacy return code.. 271 /// advance_movie(Gui * gui)272 static bool advance_movie(Gui* gui) { 273 gui->advanceMovie(); 274 return true; 275 } 276 277 /// Force immediate redraw 278 /// 279 void refreshView(); 280 281 /// Attempt to run in a fullscreen window both for plugin and 282 /// standalone player. 283 // 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(); 289 290 /// Return from fullscreen to normal mode. 291 /// 292 virtual void unsetFullscreen(); 293 294 /// Hide the menu bar when using standalone player 295 /// 296 virtual void hideMenu(); 297 298 /// Sets whether the gui should show the system mouse pointer 299 // 300 /// @param show true if the mouse should be shown. 301 /// @return true if the state changed. 302 virtual bool showMouse(bool show); 303 304 /// Sets whether the menus should be shown (for fscommand) 305 // 306 /// @param show true if the menu bar should be shown. 307 virtual void showMenu(bool show); 308 309 /// Sets whether scaling should be allowed (for fscommand) 310 // 311 /// @param allow true if stage scaling should be allowed 312 virtual void allowScale(bool allow); 313 314 // Toggle between fullscreen and normal mode 315 void toggleFullscreen(); 316 317 /// Put the application in "stop" mode 318 // 319 /// When in stop mode the application won't be advanced. 320 /// 321 void stop(); 322 323 /// Put the application in "play" mode 324 // 325 /// When in play mode the application will be advanced as usual. 326 /// 327 void play(); 328 329 /// Toggle between "stop" and "play" mode 330 // 331 /// See stop() and play() 332 /// 333 void pause(); 334 335 /// Start the movie 336 // 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. 339 /// 340 void start(); 341 342 /// See stop(), play() and pause() isStopped()343 bool isStopped() const { return _stopped; } 344 345 /// Whether gnash is is running as a plugin isPlugin()346 bool isPlugin() const { return ((_xid)); } 347 348 /// Take a screenshot now! 349 void takeScreenShot(); 350 351 /// Set the maximum number of frame advances before Gnash exits. setMaxAdvances(unsigned long ul)352 void setMaxAdvances(unsigned long ul) { if (ul) _maxAdvances = ul; } 353 showUpdatedRegions(bool x)354 void showUpdatedRegions(bool x) { _showUpdatedRegions = x; } showUpdatedRegions()355 bool showUpdatedRegions() const { return _showUpdatedRegions; } 356 357 /// Instruct the core to restart the movie and 358 /// set state to play(). This does not change pause 359 /// state. 360 void restart(); 361 362 /// Set rendering quality, if not locked by RC file.. 363 void setQuality(Quality q); 364 365 /// Get current rendering quality 366 Quality getQuality() const; 367 368 /// Toggle sound state between muted and unmuted. If 369 /// there is no active sound handler this does nothing. 370 void toggleSound(); 371 372 #ifdef GNASH_FPS_DEBUG 373 /// Set the interval between FPS debugging prints 374 // 375 /// See fpsCounterTick() 376 /// setFpsTimerInterval(float interval)377 void setFpsTimerInterval(float interval) 378 { 379 assert(interval >= 0.0); 380 fps_timer_interval = interval; 381 } 382 #endif // def GNASH_FPS_DEBUG 383 384 385 #ifdef USE_SWFTREE 386 /// Return a tree containing information about the movie playing. 387 std::unique_ptr<movie_root::InfoTree> getMovieInfo() const; 388 #endif 389 390 typedef std::map<std::string, std::string> VariableMap; 391 392 /// Add variables to set into instances of the top-level movie definition 393 void addFlashVars(VariableMap& vars); 394 395 /// Set the definition of top-level movie 396 void setMovieDefinition(movie_definition* md); 397 398 /// Set the stage to advance/display 399 void setStage(movie_root* stage); 400 401 /// Set the name of a file to dump audio to setAudioDump(const std::string & fname)402 void setAudioDump(const std::string& fname) { 403 _audioDump = fname; 404 } 405 406 /// The root movie, or "Stage" getStage()407 movie_root* getStage() { return _stage; }; 408 409 /// Handle error message from the core 410 // 411 /// @param msg The error message recieved 412 /// error(const std::string &)413 virtual void error(const std::string& /*msg*/) {} 414 415 /// Prompt user with a question she can answer with yes/no 416 // 417 /// @param question 418 /// The question to ask user 419 /// 420 /// @return 421 /// true for YES, false for NO 422 /// 423 /// The default implementation always returns true. 424 /// 425 virtual bool yesno(const std::string& question); 426 427 /// Width of a window pixel, in stage pseudopixel units. getXScale()428 float getXScale() const { return _xscale; }; 429 430 /// Height of a window pixel, in stage pseudopixel units. getYScale()431 float getYScale() const { return _yscale; }; 432 433 /// Height of a window pixel, in stage pseudopixel units. getFPS()434 float getFPS() const { return (_movieDef) ? _movieDef->get_frame_rate() : 0; 435 }; 436 437 protected: 438 439 /// Default constructor. Initialises members to safe defaults. 440 Gui(RunResources& r); 441 442 /** \brief 443 * Expanded constructor for more control over member values. 444 * 445 * @param xid The X11 Window ID to attach to. If this is argument is zero, 446 * a new window is created. 447 * 448 * @param scale The scale used to resize the window size, which has been 449 * established by extracting information from the SWF file. 450 * 451 * @param loop Defines whether or not the movie should be played once or 452 * looped indefinitely. 453 * 454 * @param depth Colour depth to be used in the client area of our window. 455 */ 456 Gui(unsigned long xid, float scale, bool loop, RunResources& r); 457 458 /// End main rendering loop calling GUI-specific exit functions. 459 // 460 /// Do not call this directly. Call quit() instead. 461 // 462 /// The default implementation calls exit(EXIT_SUCCESS), which isn't nice. 463 /// Please implement the proper main loop quitter in the subclasses. quitUI()464 virtual void quitUI() { 465 std::exit(EXIT_SUCCESS); 466 } 467 468 /// Watch a file descriptor. 469 // 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(). 473 /// 474 /// @param fd The file descriptor to be watched watchFD(int)475 virtual bool watchFD(int /* fd */) 476 { 477 log_unimpl("This GUI does not implement FD watching."); 478 return false; 479 } 480 481 482 /// Determines if playback should restart after the movie ends. 483 bool _loop; 484 485 /// The X Window ID to attach to. If zero, we create a new window. 486 unsigned long _xid; 487 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; 492 493 /// Desired window width. 494 int _width; 495 496 /// Desired window height. 497 int _height; 498 499 /// Per-run resources 500 RunResources& _runResources; 501 502 /// Main loop interval: the time between successive advance_movie calls. 503 unsigned int _interval; 504 505 /// The handler which is called to update the client area of our window. 506 std::shared_ptr<Renderer> _renderer; 507 508 /// Signals that the next frame must be re-rendered completely because the 509 /// window size did change. 510 bool _redraw_flag; 511 512 // True if Gnash is running in fullscreen 513 bool _fullscreen; 514 515 // True if mouse pointer is showing 516 bool _mouseShown; 517 518 // Maximum number of advances before exit; 0 for no limit. 519 unsigned long _maxAdvances; 520 521 /// Counter to keep track of frame advances 522 unsigned long _advances; 523 524 /// Name of a file to dump audio to 525 std::string _audioDump; 526 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) stopHook()529 virtual void stopHook() {} 530 531 /// Called by Gui::play(). playHook()532 virtual void playHook() {} 533 534 /// Determines whether the Gui is visible (not obscured). visible()535 virtual bool visible() { return true; } 536 private: 537 538 struct Display; 539 540 std::map<int /* fd */, std::function<void ()> > _fd_callbacks; 541 542 /// Width of a window pixel, in stage pseudopixel units. 543 float _xscale; 544 545 /// Height of a window pixel, in stage pseudopixel units. 546 float _yscale; 547 548 /// Window pixel X offset of stage origin 549 std::int32_t _xoffset; 550 551 /// Window pixel Y offset of stage origin 552 std::int32_t _yoffset; 553 554 bool display(movie_root* m); 555 556 #ifdef GNASH_FPS_DEBUG 557 unsigned int fps_counter; 558 559 float fps_rate_min, fps_rate_max; 560 561 // Number of calls to fpsCounterTick, which is also 562 // the number of calls to movie_advance() 563 unsigned int fps_counter_total; 564 565 std::uint64_t fps_timer, fps_start_timer; 566 567 /// The time, in seconds, between prints (which also resets the fps counter). 568 // 569 /// interval must be >= 0 570 /// 571 float fps_timer_interval; 572 573 /// Number of frames rendering of which was dropped 574 unsigned int frames_dropped; 575 576 /// \brief 577 /// Should be called on every frame advance (including inter-frames caused 578 /// by mouse events). 579 // 580 /// Based on fps-timer_interval. See setFpsTimerInterval. 581 /// 582 void fpsCounterTick(); 583 584 #endif // def GNASH_FPS_DEBUG 585 586 VariableMap _flashVars; 587 588 boost::intrusive_ptr<movie_definition> _movieDef; 589 590 /// The root movie, or "Stage" 591 movie_root* _stage; 592 593 /// True if the application has been put into "stop" mode 594 bool _stopped; 595 596 /// True if the application didn't start yet 597 bool _started; 598 599 /// If true, updated regions (invalidated ranges) are visibly outlined. 600 bool _showUpdatedRegions; 601 602 SystemClock _systemClock; 603 InterruptableVirtualClock _virtualClock; 604 605 /// Checked on each advance for screenshot activity if it exists. 606 std::unique_ptr<ScreenShotter> _screenShotter; 607 608 #ifdef ENABLE_KEYBOARD_MOUSE_MOVEMENTS 609 int _xpointer; 610 int _ypointer; 611 bool _keyboardMouseMovements; 612 int _keyboardMouseMovementsStep; 613 #endif // ENABLE_KEYBOARD_MOUSE_MOVEMENTS 614 }; 615 616 /// Named constructors 617 namespace gui { 618 std::unique_ptr<Gui> createFBGui(unsigned long xid, float scale, bool loop, RunResources& r); 619 } 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); 630 631 632 } // end of gnash namespace 633 634 // end of _GUI_H_ 635 #endif 636 637 // Local Variables: 638 // mode: C++ 639 // indent-tabs-mode: nil 640 // End: 641