@@ -32,6 +32,9 @@ SDLWindow::~SDLWindow()
32
32
{
33
33
// Restore the original gamma when we exit the client
34
34
setGamma (origGamma);
35
+
36
+ if (windowId != NULL )
37
+ SDL_DestroyWindow (windowId);
35
38
}
36
39
37
40
void SDLWindow::setTitle (const char *_title)
@@ -98,16 +101,27 @@ void SDLWindow::getMouse(int& _x, int& _y) const
98
101
99
102
void SDLWindow::setSize (int _width, int _height)
100
103
{
104
+ // workaround for two issues on Linux, where resizing by dragging the window corner causes glitching, and where
105
+ // iconifying or switching applications while using a scaled fullscreen resolution causes the non-fullscreen
106
+ // window resolution to assume the fullscreen resolution
107
+ #ifdef __linux__
108
+ if (!fullScreen)
109
+ {
110
+ base_width = _width;
111
+ base_height = _height;
112
+ }
113
+ #else
101
114
base_width = _width;
102
115
base_height = _height;
103
116
if (!fullScreen && windowId)
104
117
SDL_SetWindowSize (windowId, base_width, base_height);
118
+ #endif // __linux__
105
119
}
106
120
107
121
void SDLWindow::getSize (int & width, int & height) const
108
122
{
109
123
if (fullScreen)
110
- const_cast <SDLDisplay *>(( const SDLDisplay *) getDisplay ())->getWindowSize (width, height);
124
+ const_cast <SDLDisplay *>(static_cast < const SDLDisplay *>( getDisplay () ))->getWindowSize (width, height);
111
125
else
112
126
{
113
127
width = base_width;
@@ -148,7 +162,10 @@ void SDLWindow::swapBuffers()
148
162
if (! SDL_GL_GetSwapInterval ())
149
163
return ;
150
164
151
- const int maxRunawayFPS = 65 ;
165
+ int maxRunawayFPS = 65 ;
166
+ SDL_DisplayMode desktopDisplayMode;
167
+ if (SDL_GetDesktopDisplayMode (0 , &desktopDisplayMode) == 0 )
168
+ maxRunawayFPS = desktopDisplayMode.refresh_rate + 5 ;
152
169
153
170
static TimeKeeper lastFrame = TimeKeeper::getSunGenesisTime ();
154
171
const TimeKeeper now = TimeKeeper::getCurrent ();
@@ -165,6 +182,24 @@ void SDLWindow::swapBuffers()
165
182
#endif // __APPLE__
166
183
}
167
184
185
+ // For some reason, when creating a new fullscreen window on Linux with a different resolution than before, SDL throws
186
+ // a resize event with the old window resolution, which is not what we want. This function is called to filter SDL
187
+ // window resize events right after the resolution change and adjust the resolution to the correct one.
188
+ #ifdef __linux__
189
+ int SDLWindowEventFilter (void *resolution, SDL_Event *event)
190
+ {
191
+ if (event->type == SDL_WINDOWEVENT && (event->window .event == SDL_WINDOWEVENT_RESIZED ||
192
+ event->window .event == SDL_WINDOWEVENT_SIZE_CHANGED))
193
+ {
194
+ // adjust the window resolution to match the values passed to us
195
+ event->window .data1 = static_cast <int *>(resolution)[0 ];
196
+ event->window .data2 = static_cast <int *>(resolution)[1 ];
197
+ }
198
+
199
+ return 1 ; // allow the event
200
+ }
201
+ #endif // __linux__
202
+
168
203
bool SDLWindow::create (void )
169
204
{
170
205
int targetWidth, targetHeight;
@@ -196,17 +231,107 @@ bool SDLWindow::create(void)
196
231
}
197
232
198
233
// (re)create the window
199
- const Uint32 flags = SDL_WINDOW_OPENGL |
200
- (fullScreen ? SDL_WINDOW_FULLSCREEN : SDL_WINDOW_RESIZABLE) |
201
- (windowWasGrabbed ? SDL_WINDOW_INPUT_GRABBED : 0 );
202
-
203
- windowId = SDL_CreateWindow (
204
- title.c_str (),
205
- SDL_WINDOWPOS_UNDEFINED,
206
- SDL_WINDOWPOS_UNDEFINED,
207
- targetWidth,
208
- targetHeight,
209
- flags);
234
+
235
+ // workaround for an SDL 2 bug on Linux with the GNOME Window List extension enabled, where attempting to create a
236
+ // fullscreen window on a lower-resolution primary display while a higher-resolution secondary display is plugged in
237
+ // causes an infinite loop of window creation on the secondary display
238
+ // bug report: https://bugzilla.libsdl.org/show_bug.cgi?id=4990
239
+ #ifdef __linux__
240
+ if (! fullScreen || SDL_GetNumVideoDisplays () < 2 ) // create the window with the standard logic
241
+ {
242
+ #endif // __linux__
243
+ windowId = SDL_CreateWindow (
244
+ title.c_str (),
245
+ SDL_WINDOWPOS_UNDEFINED,
246
+ SDL_WINDOWPOS_UNDEFINED,
247
+ targetWidth,
248
+ targetHeight,
249
+ SDL_WINDOW_OPENGL |
250
+ (fullScreen ? SDL_WINDOW_FULLSCREEN : SDL_WINDOW_RESIZABLE) |
251
+ (windowWasGrabbed ? SDL_WINDOW_INPUT_GRABBED : 0 ));
252
+
253
+ // continuation of above workaround
254
+ #ifdef __linux__
255
+ }
256
+ else // create the window in windowed mode first and then switch to fullscreen
257
+ {
258
+ windowId = SDL_CreateWindow (
259
+ title.c_str (),
260
+ SDL_WINDOWPOS_UNDEFINED,
261
+ SDL_WINDOWPOS_UNDEFINED,
262
+ base_width,
263
+ base_height,
264
+ SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE | (windowWasGrabbed ? SDL_WINDOW_INPUT_GRABBED : 0 ));
265
+
266
+ SDL_DisplayMode displayMode;
267
+ if (SDL_GetDesktopDisplayMode (0 , &displayMode) < 0 )
268
+ {
269
+ printf (" Unable to get desktop display mode: %s" , SDL_GetError ());
270
+ return false ;
271
+ }
272
+ displayMode.w = targetWidth;
273
+ displayMode.h = targetHeight;
274
+ if (SDL_SetWindowDisplayMode (windowId, &displayMode))
275
+ {
276
+ printf (" Unable to set display mode: %s" , SDL_GetError ());
277
+ return false ;
278
+ }
279
+ if (SDL_SetWindowFullscreen (windowId, SDL_WINDOW_FULLSCREEN) < 0 )
280
+ {
281
+ printf (" Unable to set window to fullscreen mode: %s" , SDL_GetError ());
282
+ return false ;
283
+ }
284
+ }
285
+
286
+ // Depending on the distribution (or possibly the window manager), SDL will not recognize the new window resolution
287
+ // and will keep returning the previous resolution when SDL_GetWindowSize() is called, until a period of time has
288
+ // passed and events have been pumped. Wait up to two seconds for the correct resolution to start being returned,
289
+ // checking every quarter second, to avoid repeating the window destruction/re-creation process based on bad data.
290
+ int currentWidth, currentHeight, resCheckLoops = 0 ;
291
+
292
+ do
293
+ {
294
+ SDL_PumpEvents ();
295
+ SDL_GetWindowSize (windowId, ¤tWidth, ¤tHeight);
296
+
297
+ if (currentWidth == targetWidth && currentHeight == targetHeight)
298
+ break ;
299
+
300
+ TimeKeeper::sleep (0 .25f );
301
+ }
302
+ while (resCheckLoops++ < 8 );
303
+ #endif // __linux__
304
+
305
+ // Apply filters due to resize event issues on Linux (see the explanation above for SDLWindowEventFilter())
306
+ #ifdef __linux__
307
+ SDL_PumpEvents ();
308
+ int windowResolution[] = { targetWidth, targetHeight };
309
+ SDL_FilterEvents (&SDLWindowEventFilter, windowResolution);
310
+ #endif // __linux__
311
+
312
+ // Work around an issue with SDL on macOS where a window that gets resized by the operating system for various
313
+ // reasons (e.g., creating a window that doesn't fit between the dock and menu bar, or switching from a maximized
314
+ // window to native fullscreen then back to windowed mode) doesn't always correctly throw a resize event
315
+ #ifdef __APPLE__
316
+ SDL_PumpEvents ();
317
+
318
+ int currentWidth, currentHeight;
319
+ SDL_GetWindowSize (windowId, ¤tWidth, ¤tHeight);
320
+
321
+ if (! fullScreen && (currentWidth != targetWidth || currentHeight != targetHeight))
322
+ {
323
+ SDL_Event fakeResizeEvent;
324
+ SDL_zero (fakeResizeEvent);
325
+
326
+ fakeResizeEvent.window .type = SDL_WINDOWEVENT;
327
+ fakeResizeEvent.window .windowID = 0 ; // deliberately not matching SDL_GetWindowID() so SDL doesn't purge event
328
+ fakeResizeEvent.window .event = SDL_WINDOWEVENT_RESIZED;
329
+ fakeResizeEvent.window .data1 = currentWidth;
330
+ fakeResizeEvent.window .data2 = currentHeight;
331
+
332
+ SDL_PushEvent (&fakeResizeEvent);
333
+ }
334
+ #endif // __APPLE__
210
335
211
336
// Store the gamma immediately after creating the first window
212
337
if (origGamma < 0 )
0 commit comments