We are currently migrating Bugzilla to GitHub issues.
Any changes made to the bug tracker now will be lost, so please do not post new bugs or make changes to them.
When we're done, all bug URLs will redirect to their equivalent location on the new bug tracker.

Bug 5432

Summary: Switching to a multi-window SDL application on macOS (especially in fullscreen) always shows the last window created, and not the last focused window
Product: SDL Reporter: jackmacwindowslinux
Component: videoAssignee: Ryan C. Gordon <icculus>
Status: ASSIGNED --- QA Contact: Sam Lantinga <slouken>
Severity: normal    
Priority: P2    
Version: 2.0.12   
Hardware: x86_64   
OS: macOS 10.15   
Attachments: Recording of the focus bug

Description jackmacwindowslinux 2021-01-01 19:52:43 UTC
Created attachment 4624 [details]
Recording of the focus bug

When switching between apps using Command-Tab or the Dock on macOS, SDL will always raise the last window created, instead of whichever window was last selected or input grabbed.

To reproduce, compile this code:

#include <SDL2/SDL.h>

int main() {
    SDL_Window * win1 = SDL_CreateWindow("Window 1", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 300, 200, SDL_WINDOW_RESIZABLE);
    SDL_Window * win2 = SDL_CreateWindow("Window 2", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 300, 200, SDL_WINDOW_RESIZABLE);
    SDL_RaiseWindow(win1);
    SDL_Event e;
    while (1) if (SDL_WaitEvent(&e) && e.type == SDL_QUIT) break;
    SDL_DestroyWindow(win2);
    SDL_DestroyWindow(win1);
    return 0;
}

Then run the program, notice that Window 1 is raised, Command-Tab out to another application, and switch back via either Command-Tab or the Dock. I expect Window 1 to remain on top, but instead it raises Window 2 to the top.

I've attached a demonstration video of an app in fullscreen. I'm using the trackpad to go to the next space, but switching to the first one makes it automatically go to the second one (I'm not moving it manually). The last window being focused each time is the window with green text; however, it always switches to the one with yellow text.

I have found the source of the problem in SDL_cocoaevents.m, on lines 216-235. Currently, when the app delegate receives a focus event, it reads from SDL_GetVideoDevice()->windows, which is only set when a window is created or destroyed. Thus, the last window created and pushed to the "stack" is focused. 

My proposed solution would be to either a) have a dedicated lastFocusedWindow field in SDL_VideoDevice that is set for every SDL_RaiseWindow/focus event, and then use that in the application activation event, or b) reorder the windows list on SDL_RaiseWindow/focus to move the window to the top, which could potentially be as simple as this:

win->prev->next = win->next;
win->next->prev = win->prev;
win->prev = NULL;
win->next = _this->windows;
_this->windows = win;

I imagine there'd be more to it than that, but that should be the gist of it.

This bug may also affect other systems, but I have yet to try it out. (However, I do recall something like this possibly happening on Windows.)