OpenClonk
C4WindowSDL.cpp
Go to the documentation of this file.
1 /*
2  * OpenClonk, http://www.openclonk.org
3  *
4  * Copyright (c) 2005-2009, RedWolf Design GmbH, http://www.clonk.de/
5  * Copyright (c) 2010-2016, The OpenClonk Team and contributors
6  *
7  * Distributed under the terms of the ISC license; see accompanying file
8  * "COPYING" for details.
9  *
10  * "Clonk" is a registered trademark of Matthes Bender, used with permission.
11  * See accompanying file "TRADEMARK" for details.
12  *
13  * To redistribute this file separately, substitute the full license texts
14  * for the above references.
15  */
16 
17 /* A wrapper class to OS dependent event and window interfaces, SDL version */
18 
19 #include "C4Include.h"
20 #include "platform/C4Window.h"
21 
22 #include "C4Version.h"
23 #include "lib/C4Rect.h"
24 #include "editor/C4Console.h"
26 #include "game/C4Application.h"
27 #include "graphics/C4DrawGL.h"
28 #include "gui/C4Gui.h"
29 
30 #ifdef SDL_VIDEO_DRIVER_X11
31 #include <X11/Xlib.h>
32 #include <X11/Xutil.h>
33 #include <SDL_syswm.h>
34 #endif
35 
36 /* C4Window */
37 
39  Active(false), pSurface(nullptr), eKind(W_Fullscreen), window(nullptr)
40 #ifdef WITH_QT_EDITOR
41 , glwidget(nullptr)
42 #endif
43 {
44 }
45 
47 {
48  Clear();
49 }
50 
51 static void SetMultisamplingAttributes(int samples)
52 {
53  SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, samples > 0 ? 1 : 0);
54  SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, samples);
55 }
56 
57 // TODO: This is pretty slow and looks weird on Wayland
58 static void EnumerateMultiSamplesSDL(std::vector<int>& samples)
59 {
60  int max_samples;
61  glGetIntegerv(GL_MAX_SAMPLES, &max_samples);
62  // we seem to get 0 sometimes, default to trying up to 16
63  max_samples = std::max(max_samples, 16);
64  samples.clear();
65  for (int s = 2; s <= max_samples; s *= 2)
66  {
67  // Not all multisampling options seem to work. Verify by creating a hidden window.
68  SetMultisamplingAttributes(s);
69  SDL_Window *wnd = SDL_CreateWindow("OpenClonk Test Window", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 100, 100, SDL_WINDOW_OPENGL | SDL_WINDOW_HIDDEN);
70  if (wnd)
71  {
72  SDL_DestroyWindow(wnd);
73  samples.push_back(s);
74  }
75  else
76  break;
77  }
78  SetMultisamplingAttributes(Config.Graphics.MultiSampling);
79 }
80 
81 C4Window * C4Window::Init(WindowKind windowKind, C4AbstractApp * pApp, const char * Title, const C4Rect * size)
82 {
83  eKind = windowKind;
84 #ifdef WITH_QT_EDITOR
85  if (windowKind == W_Viewport)
86  {
87  // embed into editor: Viewport widget creation handled by C4ConsoleQt
88  ::Console.AddViewport(static_cast<C4ViewportWindow *>(this));
89  return this;
90  }
91 #endif
92 /* SDL_GL_MULTISAMPLEBUFFERS,
93  SDL_GL_MULTISAMPLESAMPLES,*/
94  SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
95  SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
96  SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);
97  SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 8);
98  SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, /*REQUESTED_GL_CTX_MAJOR*/ 3);
99  SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, /*REQUESTED_GL_CTX_MINOR*/ 2);
100  SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, (Config.Graphics.DebugOpenGL ? SDL_GL_CONTEXT_DEBUG_FLAG : 0));
101  SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
102  EnumerateMultiSamplesSDL(available_samples);
103  int samples = 0; // Default to initializing without AA if nothing was available
104  for (auto e : available_samples)
105  if (samples < e && e <= Config.Graphics.MultiSampling)
106  samples = e;
107  SetMultisamplingAttributes(samples);
108  uint32_t flags = SDL_WINDOW_OPENGL;
109  if (windowKind == W_Fullscreen && size->Wdt == -1)
110  flags |= SDL_WINDOW_FULLSCREEN_DESKTOP;
111  else if (windowKind == W_Fullscreen && !Config.Graphics.Windowed)
112  flags |= SDL_WINDOW_FULLSCREEN;
113  window = SDL_CreateWindow(Title, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, size->Wdt, size->Hgt, flags);
114  if (!window)
115  {
116  Log(SDL_GetError());
117  return nullptr;
118  }
119  Config.Graphics.MultiSampling = samples;
120  SDL_SetWindowData(window, "C4Window", this);
121  Active = true;
122  SDL_ShowCursor(SDL_DISABLE);
123  return this;
124 }
125 
127 {
128  // TODO: Is there some way to do this without requiring a restart?
129  // Maybe re-call SDL_SetVideoMode?
130  C4GUI::TheScreen.ShowMessage(LoadResStr("IDS_CTL_ANTIALIASING_RESTART_MSG"), LoadResStr("IDS_CTL_ANTIALIASING_RESTART_TITLE"), C4GUI::Ico_Notify);
131  return true;
132 }
133 
134 void C4Window::Clear()
135 {
136  if (window) SDL_DestroyWindow(window);
137  window = nullptr;
138 
139 #ifdef WITH_QT_EDITOR
140  if (eKind == W_Viewport)
141  {
142  // embed into editor: Viewport widget creation handled by C4ConsoleQt
143  ::Console.RemoveViewport(static_cast<C4ViewportWindow *>(this));
144  }
145 #endif
146 }
147 
148 void C4Window::EnumerateMultiSamples(std::vector<int>& samples, int min_expected) const
149 {
150  samples = available_samples;
151 }
152 
153 bool C4Window::StorePosition(const char *, const char *, bool) { return true; }
154 
155 bool C4Window::RestorePosition(const char *, const char *, bool) { return true; }
156 
157 // Window size is automatically managed by C4AbstractApp's display mode management.
158 // Just remember the size for others to query.
159 
160 bool C4Window::GetSize(C4Rect * pRect)
161 {
162  pRect->x = pRect->y = 0;
163  SDL_GL_GetDrawableSize(window, &pRect->Wdt, &pRect->Hgt);
164  return true;
165 }
166 
167 void C4Window::SetSize(unsigned int X, unsigned int Y)
168 {
169  SDL_SetWindowSize(window, X, Y);
170 }
171 
172 void C4Window::SetTitle(const char * Title)
173 {
174  SDL_SetWindowTitle(window, Title);
175 }
176 
178 {
179  // just invoke directly
180  PerformUpdate();
181 }
182 
183 static void SetUrgencyHint(SDL_Window *window, bool urgency_hint)
184 {
185 #ifdef SDL_VIDEO_DRIVER_X11
186  SDL_SysWMinfo wminfo;
187  SDL_VERSION(&wminfo.version);
188  if (!SDL_GetWindowWMInfo(window, &wminfo))
189  {
190  LogF("FlashWindow SDL: %s", SDL_GetError());
191  return;
192  }
193 
194  if (wminfo.subsystem == SDL_SYSWM_X11)
195  {
196  auto x11 = wminfo.info.x11;
197  XWMHints *wmhints = XGetWMHints(x11.display, x11.window);
198  if (wmhints == nullptr)
199  wmhints = XAllocWMHints();
200  // Set the window's urgency hint.
201  if (urgency_hint)
202  wmhints->flags |= XUrgencyHint;
203  else
204  wmhints->flags &= ~XUrgencyHint;
205  XSetWMHints(x11.display, x11.window, wmhints);
206  XFree(wmhints);
207  }
208 #endif
209 }
210 
212 {
213  SetUrgencyHint(window, true);
214 }
215 
216 void C4Window::GrabMouse(bool grab)
217 {
218  SDL_SetWindowGrab(window, grab ? SDL_TRUE : SDL_FALSE);
219 }
220 
221 void C4Window::HandleSDLEvent(SDL_WindowEvent &e)
222 {
223  switch (e.event)
224  {
225  case SDL_WINDOWEVENT_FOCUS_GAINED:
226  SetUrgencyHint(window, false);
227  break;
228  case SDL_WINDOWEVENT_RESIZED:
229  case SDL_WINDOWEVENT_SIZE_CHANGED:
230  Application.OnResolutionChanged(e.data1, e.data2);
231  break;
232  default:
233  // We don't care about most events. We should care about more, though.
234  break;
235  }
236 }
#define X(sdl, oc)
#define s
C4Config Config
Definition: C4Config.cpp:930
C4Console Console
Definition: C4Globals.cpp:45
C4Application Application
Definition: C4Globals.cpp:44
const char * LoadResStr(const char *id)
Definition: C4Language.h:83
bool Log(const char *szMessage)
Definition: C4Log.cpp:204
bool LogF(const char *strMessage,...)
Definition: C4Log.cpp:262
void OnResolutionChanged(unsigned int iXRes, unsigned int iYRes) override
int32_t DebugOpenGL
Definition: C4Config.h:117
int32_t MultiSampling
Definition: C4Config.h:115
int32_t Windowed
Definition: C4Config.h:107
C4ConfigGraphics Graphics
Definition: C4Config.h:257
void AddViewport(C4ViewportWindow *cvp)
Definition: C4ConsoleGUI.h:110
void RemoveViewport(C4ViewportWindow *cvp)
Definition: C4ConsoleGUI.h:111
bool ShowMessage(const char *szMessage, const char *szCaption, Icons icoIcon, int32_t *piConfigDontShowAgainSetting=nullptr)
Definition: C4Rect.h:28
int32_t y
Definition: C4Rect.h:30
int32_t Hgt
Definition: C4Rect.h:30
int32_t Wdt
Definition: C4Rect.h:30
int32_t x
Definition: C4Rect.h:30
virtual void EnumerateMultiSamples(std::vector< int > &samples, int min_expected=0) const
Definition: C4AppT.cpp:105
virtual C4Window * Init(WindowKind windowKind, C4AbstractApp *pApp, const char *Title, const C4Rect *size)
Definition: C4AppT.cpp:109
bool GetSize(C4Rect *pRect)
Definition: C4AppT.cpp:108
virtual bool ReInit(C4AbstractApp *pApp)
Definition: C4AppT.cpp:110
virtual ~C4Window()
Definition: C4WindowSDL.cpp:46
void SetTitle(const char *Title)
Definition: C4AppT.cpp:114
virtual void PerformUpdate()
Definition: C4App.cpp:85
bool RestorePosition(const char *szWindowName, const char *szSubKey, bool fHidden=false)
Definition: C4AppT.cpp:111
virtual void Clear()
Definition: C4AppT.cpp:102
void FlashWindow()
Definition: C4AppMac.mm:75
void SetSize(unsigned int cx, unsigned int cy)
Definition: C4AppT.cpp:113
WindowKind eKind
Definition: C4Window.h:276
virtual void RequestUpdate()
Definition: C4AppT.cpp:112
bool StorePosition(const char *szWindowName, const char *szSubKey, bool fStoreSize=true)
bool Active
Definition: C4Window.h:274
@ W_Fullscreen
Definition: C4Window.h:268
@ W_Viewport
Definition: C4Window.h:267
void GrabMouse(bool grab)
Definition: C4AppT.cpp:107
Screen TheScreen
Definition: C4Gui.cpp:1054
@ Ico_Notify
Definition: C4Gui.h:642