1 /** \file SDLGUI.h \brief Contains SDLGUI, the input driver for using SDL with
2     GG. */
3 
4 #ifndef _SDLGUI_h_
5 #define _SDLGUI_h_
6 
7 #include <GG/GUI.h>
8 
9 #include <SDL2/SDL.h>
10 #include <SDL2/SDL_keyboard.h>
11 
12 
13 class Framebuffer;
14 
15 /** \brief This is an abstract singleton class that represents the GUI
16     framework of an SDL OpenGL application.
17 
18     <p>Usage:
19 
20     <br>Any application including an object of this class should declare that
21     object as a local variable in main(). The name of this variable will
22     herein be assumed to be "gui". It should be allocated on the stack; if it
23     is created dynamically a leak may occur. SDLGUI is designed so the main()
24     of the application can consist of just the one line "gui();".
25 
26     <p>To do this, the user needs only to override the Initialize() and
27     FinalCleanup() methods, and ensure that the program does not terminate
28     abnormally; this ensures FinalCleanup() is called when gui's destructor is
29     invoked. ExitApp() can also perform cleanup and terminate the application
30     cleanly.
31 
32     <p>Most of the member methods of SDLGUI have been declared virtual, to
33     give the user great control when subclassing. The virtual function calls
34     are usually not a performance issue, since none of the methods is called
35     repeatedly, except HandleEvent(); if this is a problem, just create a new
36     function in your subclass and call that from within Run() instead of
37     HandleEvent(). Note that though the bulk of the program execution takes
38     place within Run(), Run() itself is also only called once.
39 
40     <p>SDLGUI takes a two-tiered approach to event handling.  The event pump
41     calls HandleSystemEvents(), which polls for SDL events and handles them by
42     first determining whether the event is GG-related, or some other non-GG
43     event, such as SDL_QUIT, etc.  GG events and non-GG events are passed to
44     HandleGGEvent() and HandleNonGGEvent(), respectively.  For most uses,
45     there should be no need to override the behavior of HandleSDLEvents().
46     However, the HandleNonGGEvent() default implementation only responds to
47     SDL_QUIT events, and so should be overridden in most cases. */
48 class SDLGUI : public GG::GUI
49 {
50 public:
51     /** \name Structors */ ///@{
52     explicit SDLGUI(int w = 1024, int h = 768, bool calc_FPS = false, const std::string& app_name = "GG",
53                     int x = SDL_WINDOWPOS_UNDEFINED, int y = SDL_WINDOWPOS_UNDEFINED, bool fullscreen = false,
54                     bool fake_mode_change = false);
55 
56     virtual ~SDLGUI();
57     //@}
58 
59     /** \name Accessors */ ///@{
60     GG::X AppWidth() const override;
61     GG::Y AppHeight() const override;
62     unsigned int Ticks() const override;
63     std::string ClipboardText() const override;
64     virtual std::vector<std::string> GetSupportedResolutions() const override;
65     virtual GG::Pt GetDefaultResolution (int display_id) const override;
66 
67     virtual bool Fullscreen() const final;
68     virtual bool FakeModeChange() const final;
69     //@}
70 
71     /** \name Mutators */ ///@{
72     void ExitApp(int code = 0) override;
73     bool SetClipboardText(const std::string& text) override;
74 
75     void Enter2DMode() override;
76     void Exit2DMode() override;
77 
78     void HandleSystemEvents() override;
79 
80     void RenderBegin() override;
81     void RenderEnd() override;
82 
83     void Run() override;
84 
85     bool AppHasMouseFocus() const override;
86 
87     void            SetWindowTitle(const std::string& title);
88     void            SetVideoMode(GG::X width, GG::Y height, bool fullscreen, bool fake_mode_change);
89     //@}
90 
91     static SDLGUI*  GetGUI();                             ///< allows any code to access the gui framework by calling SDLGUI::GetGUI()
92 
93     static  GG::Pt  GetDefaultResolutionStatic(int display_id);
94     static int      NumVideoDisplaysStatic();
95     bool            FramebuffersAvailable() const;
96 
97     /** Returns the largest possible width if all displays are aligned horizontally.
98         Ideally it reports actual desktop width using all displays.*/
99     static int MaximumPossibleWidth();
100     /** Returns the largest possible height if all displays are aligned vertically.
101         Ideally it reports the actual desktop height using all displays.*/
102     static int MaximumPossibleHeight();
103 protected:
104     void SetAppSize(const GG::Pt& size);
105 
106     // these are called at the beginning of the gui's execution
107     /** Initializes SDL, FE, and SDL OpenGL functionality. */
108     void SDLInit();
109 
110     /** Allows user to specify OpenGL initialization code;
111         called at the end of SDLInit(). */
112     void GLInit();
113 
114     /** Provides one-time gui initialization. */
115     virtual void Initialize() = 0;
116 
117     /** event handler for all SDL events that are not GG-related. */
118     void HandleNonGGEvent(const SDL_Event& event);
119 
120     // these are called at the end of the gui's execution
121     /** Provides one-time gui cleanup. */
122     void FinalCleanup();
123 
124     /** Cleans up SDL and (if used) FE. */
125     void SDLQuit();
126 
127     void ResetFramebuffer(); ///< Resizes or deletes the framebuffer for fake fullscreen.
128 
129     /** Given is_width = true (false) it returns the largest possible window
130         width (height) if all displays are aligned horizontally (vertically).
131         Ideally it returns the actual width (height) of a multi-monitor display.*/
132     static int MaximumPossibleDimension(bool is_width = true);
133 
134 private:
135     void RelayTextInput (const SDL_TextInputEvent& text, GG::Pt mouse_pos);
136     /** Bare minimum SDL video initialization to allow queries to display sizes etc.
137         If called during static initialization, it will cause OSX to crash on exit. */
138     static void SDLMinimalInit();
139 
140     GG::X           m_app_width{1024};      ///< application width and height (defaults to 1024 x 768)
141     GG::Y           m_app_height{768};
142     GG::X           m_initial_x{0};         ///< The initial position of the application window
143     GG::Y           m_initial_y{0};
144     bool            m_fullscreen = false;
145     bool            m_fake_mode_change = false;
146     int             m_display_id = 0;
147     SDL_Window*     m_window = nullptr;     ///< The sdl window
148     SDL_GLContext   m_gl_context = nullptr; ///< The OpenGL context
149     bool            m_done = false;         ///< Set true true when we should exit.
150 
151     /** Virtual screen for fake fullscreen.  Equals nullptr ifi
152         m_fake_mode_change == false. */
153     std::unique_ptr<Framebuffer> m_framebuffer;
154 };
155 
156 #endif
157