Skip to content
This repository was archived by the owner on Jan 5, 2024. It is now read-only.

Commit 4856501

Browse files
committed
Rework window event handling to fix bullshit with focus events and mouse binding while in multiscreen fullscreen splitscreen screenscreen screenscreenscreen AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA (followup to d4cd433)
PLS DON'T SHIT SELF UNDER SOME DUMBASS EDGE CASE PLS AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
1 parent d00da27 commit 4856501

File tree

3 files changed

+69
-34
lines changed

3 files changed

+69
-34
lines changed

Main.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,7 @@ namespace RTE {
171171
System::SetQuit(true);
172172
return;
173173
}
174-
g_WindowMan.HandleWindowEvent(sdlEvent);
174+
g_WindowMan.QueueWindowEvent(sdlEvent);
175175
break;
176176
case SDL_KEYUP:
177177
case SDL_KEYDOWN:

Managers/WindowMan.cpp

Lines changed: 58 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,16 @@ namespace RTE {
1515
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1616

1717
void WindowMan::Clear() {
18+
m_EventQueue.clear();
19+
m_FocusEventsDispatchedByMovingBetweenWindows = false;
20+
m_FocusEventsDispatchedByDisplaySwitchIn = false;
21+
1822
m_PrimaryTexture.reset();
1923
m_PrimaryRenderer.reset();
2024
m_PrimaryWindow.reset();
2125
ClearMultiDisplayData();
2226

2327
m_AnyWindowHasFocus = false;
24-
m_FocusLostDueToMovingBetweenGameWindows = false;
2528
m_ResolutionChanged = false;
2629

2730
m_NumDisplays = 0;
@@ -506,13 +509,16 @@ namespace RTE {
506509

507510
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
508511

509-
void WindowMan::DisplaySwitchIn() const {
512+
void WindowMan::DisplaySwitchIn(SDL_Window *windowThatShouldTakeInputFocus) const {
510513
g_UInputMan.DisableMouseMoving(false);
511514
if (!m_MultiDisplayWindows.empty()) {
512-
SDL_RaiseWindow(m_PrimaryWindow.get());
513-
for (const std::shared_ptr<SDL_Window> &window : m_MultiDisplayWindows) {
515+
for (const auto &window : m_MultiDisplayWindows) {
514516
SDL_RaiseWindow(window.get());
515517
}
518+
SDL_RaiseWindow(windowThatShouldTakeInputFocus);
519+
SDL_SetWindowInputFocus(windowThatShouldTakeInputFocus);
520+
} else {
521+
SDL_RaiseWindow(m_PrimaryWindow.get());
516522
}
517523
}
518524

@@ -524,35 +530,59 @@ namespace RTE {
524530

525531
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
526532

527-
void WindowMan::HandleWindowEvent(const SDL_Event &windowEvent) {
528-
switch (windowEvent.window.event) {
529-
case SDL_WINDOWEVENT_FOCUS_GAINED:
530-
if (!m_FocusLostDueToMovingBetweenGameWindows) {
531-
DisplaySwitchIn();
532-
}
533-
m_AnyWindowHasFocus = true;
534-
break;
535-
case SDL_WINDOWEVENT_FOCUS_LOST:
536-
m_AnyWindowHasFocus = false;
537-
m_FocusLostDueToMovingBetweenGameWindows = FullyCoversAllDisplays();
538-
DisplaySwitchOut();
539-
break;
540-
case SDL_WINDOWEVENT_ENTER:
541-
if (m_AnyWindowHasFocus && FullyCoversAllDisplays()) {
542-
SDL_RaiseWindow(SDL_GetWindowFromID(windowEvent.window.windowID));
543-
SDL_SetWindowInputFocus(SDL_GetWindowFromID(windowEvent.window.windowID));
544-
m_AnyWindowHasFocus = true;
545-
}
546-
break;
547-
default:
548-
break;
549-
}
533+
void WindowMan::QueueWindowEvent(const SDL_Event &windowEvent) {
534+
m_EventQueue.emplace_back(windowEvent);
550535
}
551536

552537
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
553538

554539
void WindowMan::Update() {
555-
m_FocusLostDueToMovingBetweenGameWindows = false;
540+
// Some bullshit we have to deal with to correctly focus windows in multi-display fullscreen so mouse binding/unbinding works correctly. Not relevant for single window.
541+
// This is SDL's fault for not having handling to raise a window so it's top-most without taking focus of it.
542+
// Don't process any focus events this update if either of these has been set in the previous one.
543+
// Having two flags is a bit redundant but better be safe than recursively raising windows and taking focus and pretty much locking up your whole shit so the only thing you can do about it is sign out to terminate this.
544+
// Clearing the queue here is just us not handling the events on our end. Whatever they are and do and wherever they propagate to is handled by SDL_PollEvent earlier.
545+
if (m_FocusEventsDispatchedByDisplaySwitchIn || m_FocusEventsDispatchedByMovingBetweenWindows) {
546+
m_EventQueue.clear();
547+
548+
m_FocusEventsDispatchedByDisplaySwitchIn = false;
549+
m_FocusEventsDispatchedByMovingBetweenWindows = false;
550+
return;
551+
}
552+
553+
SDL_Event windowEvent;
554+
for (std::vector<SDL_Event>::const_iterator eventIterator = m_EventQueue.begin(); eventIterator != m_EventQueue.end(); eventIterator++) {
555+
windowEvent = *eventIterator;
556+
int windowID = windowEvent.window.windowID;
557+
558+
switch (windowEvent.window.event) {
559+
case SDL_WINDOWEVENT_ENTER:
560+
if (SDL_GetWindowID(SDL_GetMouseFocus()) > 0 && m_AnyWindowHasFocus && FullyCoversAllDisplays()) {
561+
for (const auto &window : m_MultiDisplayWindows) {
562+
SDL_RaiseWindow(window.get());
563+
}
564+
SDL_RaiseWindow(SDL_GetWindowFromID(windowID));
565+
SDL_SetWindowInputFocus(SDL_GetWindowFromID(windowID));
566+
m_AnyWindowHasFocus = true;
567+
m_FocusEventsDispatchedByMovingBetweenWindows = true;
568+
}
569+
break;
570+
case SDL_WINDOWEVENT_FOCUS_GAINED:
571+
DisplaySwitchIn(SDL_GetWindowFromID(windowID));
572+
m_AnyWindowHasFocus = true;
573+
m_FocusEventsDispatchedByDisplaySwitchIn = true;
574+
break;
575+
case SDL_WINDOWEVENT_FOCUS_LOST:
576+
DisplaySwitchOut();
577+
m_AnyWindowHasFocus = false;
578+
m_FocusEventsDispatchedByDisplaySwitchIn = false;
579+
m_FocusEventsDispatchedByMovingBetweenWindows = false;
580+
break;
581+
default:
582+
break;
583+
}
584+
}
585+
m_EventQueue.clear();
556586
}
557587

558588
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

Managers/WindowMan.h

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -193,10 +193,10 @@ namespace RTE {
193193

194194
#pragma region Concrete Methods
195195
/// <summary>
196-
/// Handles window events coming from the SDL event queue.
196+
/// Adds an SDL_Event to the Event queue for processing on Update.
197197
/// </summary>
198-
/// <param name="windowEvent">The SDL event to handle.</param>
199-
void HandleWindowEvent(const SDL_Event &windowEvent);
198+
/// <param name="windowEvent">The SDL window event to queue.</param>
199+
void QueueWindowEvent(const SDL_Event &windowEvent);
200200

201201
/// <summary>
202202
/// Updates the state of this WindowMan.
@@ -216,6 +216,11 @@ namespace RTE {
216216

217217
private:
218218

219+
std::vector<SDL_Event> m_EventQueue; //!< List of incoming window events.
220+
221+
bool m_FocusEventsDispatchedByMovingBetweenWindows; //!< Whether queued events were dispatched due to raising windows when moving between windows in multi-display fullscreen in the previous update.
222+
bool m_FocusEventsDispatchedByDisplaySwitchIn; //!< Whether queued events were dispatched due to raising windows when taking focus of any game window in the previous update.
223+
219224
std::shared_ptr<SDL_Window> m_PrimaryWindow; //!< The main window.
220225
std::shared_ptr<SDL_Renderer> m_PrimaryRenderer; //!< The main window renderer, draws to the main window.
221226
std::unique_ptr<SDL_Texture, SDLTextureDeleter> m_PrimaryTexture; //!< The main window renderer's drawing surface.
@@ -226,7 +231,6 @@ namespace RTE {
226231
std::vector<SDL_Rect> m_MultiDisplayTextureOffsets; //!< Texture offsets for multi-display fullscreen.
227232

228233
bool m_AnyWindowHasFocus; //!< Whether any game window has focus.
229-
bool m_FocusLostDueToMovingBetweenGameWindows; //!< Whether the focus lost event was due to moving between displays while in multi-display fullscreen.
230234
bool m_ResolutionChanged; //!< Whether the resolution was changed through the settings.
231235

232236
int m_NumDisplays; //!< Number of physical displays.
@@ -311,7 +315,8 @@ namespace RTE {
311315
/// <summary>
312316
/// Handles focus gain when switching back to the game window.
313317
/// </summary>
314-
void DisplaySwitchIn() const;
318+
/// <param name="windowThatShouldTakeInputFocus">The window that should take focus of input after all the windows are raised. This is only relevant in multi-display fullscreen.</param>
319+
void DisplaySwitchIn(SDL_Window *windowThatShouldTakeInputFocus) const;
315320

316321
/// <summary>
317322
/// Handles focus loss when switching away from the game window.

0 commit comments

Comments
 (0)