diff --git a/src/video/SDL_video.c b/src/video/SDL_video.c index d1e24eaaa0..2a5b419a24 100644 --- a/src/video/SDL_video.c +++ b/src/video/SDL_video.c @@ -1562,6 +1562,10 @@ void SDL_RelativeToGlobalForWindow(SDL_Window *window, int rel_x, int rel_y, int for (w = window->parent; w; w = w->parent) { rel_x += w->x; rel_y += w->y; + + if (!SDL_WINDOW_IS_POPUP(w)) { + break; + } } } @@ -1582,6 +1586,10 @@ void SDL_GlobalToRelativeForWindow(SDL_Window *window, int abs_x, int abs_y, int for (w = window->parent; w; w = w->parent) { abs_x -= w->x; abs_y -= w->y; + + if (!SDL_WINDOW_IS_POPUP(w)) { + break; + } } } diff --git a/src/video/cocoa/SDL_cocoawindow.m b/src/video/cocoa/SDL_cocoawindow.m index bafeda0ddd..4f51a514fe 100644 --- a/src/video/cocoa/SDL_cocoawindow.m +++ b/src/video/cocoa/SDL_cocoawindow.m @@ -622,26 +622,29 @@ static void Cocoa_UpdateClipCursor(SDL_Window *window) } } -static SDL_Window *GetTopmostWindow(SDL_Window *window) +static SDL_Window *GetParentToplevelWindow(SDL_Window *window) { - SDL_Window *topmost = window; + SDL_Window *toplevel = window; // Find the topmost parent - while (topmost->parent != NULL) { - topmost = topmost->parent; + while (SDL_WINDOW_IS_POPUP(toplevel)) { + toplevel = toplevel->parent; } - return topmost; + return toplevel; } static void Cocoa_SetKeyboardFocus(SDL_Window *window) { - SDL_Window *topmost = GetTopmostWindow(window); - SDL_CocoaWindowData *topmost_data; + SDL_Window *toplevel = GetParentToplevelWindow(window); + SDL_CocoaWindowData *toplevel_data; - topmost_data = (__bridge SDL_CocoaWindowData *)topmost->internal; - topmost_data.keyboard_focus = window; - SDL_SetKeyboardFocus(window); + toplevel_data = (__bridge SDL_CocoaWindowData *)toplevel->internal; + toplevel_data.keyboard_focus = window; + + if (!window->is_hiding && !window->is_destroying) { + SDL_SetKeyboardFocus(window); + } } static void Cocoa_SendExposedEventIfVisible(SDL_Window *window) @@ -2555,8 +2558,8 @@ void Cocoa_HideWindow(SDL_VideoDevice *_this, SDL_Window *window) if (window == SDL_GetKeyboardFocus()) { SDL_Window *new_focus = window->parent; - // Find the highest level window that isn't being hidden or destroyed. - while (new_focus->parent != NULL && (new_focus->is_hiding || new_focus->is_destroying)) { + // Find the highest level window, up to the next toplevel, that isn't being hidden or destroyed. + while (SDL_WINDOW_IS_POPUP(new_focus) && (new_focus->is_hiding || new_focus->is_destroying)) { new_focus = new_focus->parent; } @@ -2988,7 +2991,7 @@ void Cocoa_DestroyWindow(SDL_VideoDevice *_this, SDL_Window *window) NSArray *contexts; #endif // SDL_VIDEO_OPENGL - SDL_Window *topmost = GetTopmostWindow(window); + SDL_Window *topmost = GetParentToplevelWindow(window); SDL_CocoaWindowData *topmost_data = (__bridge SDL_CocoaWindowData *)topmost->internal; /* Reset the input focus of the root window if this window is still set as keyboard focus. @@ -2998,7 +3001,7 @@ void Cocoa_DestroyWindow(SDL_VideoDevice *_this, SDL_Window *window) */ if (topmost_data.keyboard_focus == window) { SDL_Window *new_focus = window; - while (new_focus->parent && (new_focus->is_hiding || new_focus->is_destroying)) { + while (SDL_WINDOW_IS_POPUP(new_focus) && (new_focus->is_hiding || new_focus->is_destroying)) { new_focus = new_focus->parent; } diff --git a/src/video/wayland/SDL_waylandwindow.c b/src/video/wayland/SDL_waylandwindow.c index 4b2616de7f..75e80af4ee 100644 --- a/src/video/wayland/SDL_waylandwindow.c +++ b/src/video/wayland/SDL_waylandwindow.c @@ -1631,16 +1631,18 @@ static const struct frog_color_managed_surface_listener frog_surface_listener = static void SetKeyboardFocus(SDL_Window *window) { - SDL_Window *topmost = window; + SDL_Window *toplevel = window; - // Find the topmost parent - while (topmost->parent) { - topmost = topmost->parent; + // Find the toplevel parent + while (SDL_WINDOW_IS_POPUP(toplevel)) { + toplevel = toplevel->parent; } - topmost->internal->keyboard_focus = window; + toplevel->internal->keyboard_focus = window; - SDL_SetKeyboardFocus(window); + if (!window->is_hiding && !window->is_destroying) { + SDL_SetKeyboardFocus(window); + } } bool Wayland_SetWindowHitTest(SDL_Window *window, bool enabled) @@ -2043,8 +2045,8 @@ static void Wayland_ReleasePopup(SDL_VideoDevice *_this, SDL_Window *popup) if (popup == SDL_GetKeyboardFocus()) { SDL_Window *new_focus = popup->parent; - // Find the highest level window that isn't being hidden or destroyed. - while (new_focus->parent && (new_focus->is_hiding || new_focus->is_destroying)) { + // Find the highest level window, up to the toplevel parent, that isn't being hidden or destroyed. + while (SDL_WINDOW_IS_POPUP(new_focus) && new_focus->parent && (new_focus->is_hiding || new_focus->is_destroying)) { new_focus = new_focus->parent; } diff --git a/src/video/windows/SDL_windowsevents.c b/src/video/windows/SDL_windowsevents.c index de3d3a6a2c..51fbbe9f9c 100644 --- a/src/video/windows/SDL_windowsevents.c +++ b/src/video/windows/SDL_windowsevents.c @@ -1533,8 +1533,8 @@ LRESULT CALLBACK WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lPara // Update the position of any child windows for (win = data->window->first_child; win; win = win->next_sibling) { - // Don't update hidden child windows, their relative position doesn't change - if (!(win->flags & SDL_WINDOW_HIDDEN)) { + // Don't update hidden child popup windows, their relative position doesn't change + if (SDL_WINDOW_IS_POPUP(win) && !(win->flags & SDL_WINDOW_HIDDEN)) { WIN_SetWindowPositionInternal(win, SWP_NOCOPYBITS | SWP_NOACTIVATE, SDL_WINDOWRECT_CURRENT); } } diff --git a/src/video/windows/SDL_windowswindow.c b/src/video/windows/SDL_windowswindow.c index 0286aaf33c..d4456cab3b 100644 --- a/src/video/windows/SDL_windowswindow.c +++ b/src/video/windows/SDL_windowswindow.c @@ -687,7 +687,7 @@ static void WIN_ConstrainPopup(SDL_Window *window, bool output_to_pending) int offset_x = 0, offset_y = 0; // Calculate the total offset from the parents - for (w = window->parent; w->parent; w = w->parent) { + for (w = window->parent; SDL_WINDOW_IS_POPUP(w); w = w->parent) { offset_x += w->x; offset_y += w->y; } @@ -725,15 +725,18 @@ static void WIN_ConstrainPopup(SDL_Window *window, bool output_to_pending) static void WIN_SetKeyboardFocus(SDL_Window *window) { - SDL_Window *topmost = window; + SDL_Window *toplevel = window; // Find the topmost parent - while (topmost->parent) { - topmost = topmost->parent; + while (SDL_WINDOW_IS_POPUP(toplevel)) { + toplevel = toplevel->parent; } - topmost->internal->keyboard_focus = window; - SDL_SetKeyboardFocus(window); + toplevel->internal->keyboard_focus = window; + + if (!window->is_hiding && !window->is_destroying) { + SDL_SetKeyboardFocus(window); + } } bool WIN_CreateWindow(SDL_VideoDevice *_this, SDL_Window *window, SDL_PropertiesID create_props) @@ -1118,8 +1121,8 @@ void WIN_HideWindow(SDL_VideoDevice *_this, SDL_Window *window) if (window == SDL_GetKeyboardFocus()) { SDL_Window *new_focus = window->parent; - // Find the highest level window that isn't being hidden or destroyed. - while (new_focus->parent && (new_focus->is_hiding || new_focus->is_destroying)) { + // Find the highest level window, up to the toplevel parent, that isn't being hidden or destroyed. + while (SDL_WINDOW_IS_POPUP(new_focus) && (new_focus->is_hiding || new_focus->is_destroying)) { new_focus = new_focus->parent; } diff --git a/src/video/x11/SDL_x11events.c b/src/video/x11/SDL_x11events.c index ad46ffbd0d..9baf943aa6 100644 --- a/src/video/x11/SDL_x11events.c +++ b/src/video/x11/SDL_x11events.c @@ -1382,8 +1382,8 @@ static void X11_DispatchEvent(SDL_VideoDevice *_this, XEvent *xevent) } #endif for (w = data->window->first_child; w; w = w->next_sibling) { - // Don't update hidden child windows, their relative position doesn't change - if (!(w->flags & SDL_WINDOW_HIDDEN)) { + // Don't update hidden child popup windows, their relative position doesn't change + if (SDL_WINDOW_IS_POPUP(w) && !(w->flags & SDL_WINDOW_HIDDEN)) { X11_UpdateWindowPosition(w, true); } } diff --git a/src/video/x11/SDL_x11window.c b/src/video/x11/SDL_x11window.c index 816f51d537..791d515e19 100644 --- a/src/video/x11/SDL_x11window.c +++ b/src/video/x11/SDL_x11window.c @@ -208,7 +208,7 @@ static void X11_ConstrainPopup(SDL_Window *window, bool output_to_pending) int offset_x = 0, offset_y = 0; // Calculate the total offset from the parents - for (w = window->parent; w->parent; w = w->parent) { + for (w = window->parent; SDL_WINDOW_IS_POPUP(w); w = w->parent) { offset_x += w->x; offset_y += w->y; } @@ -242,15 +242,18 @@ static void X11_ConstrainPopup(SDL_Window *window, bool output_to_pending) static void X11_SetKeyboardFocus(SDL_Window *window) { - SDL_Window *topmost = window; + SDL_Window *toplevel = window; - // Find the topmost parent - while (topmost->parent) { - topmost = topmost->parent; + // Find the toplevel parent + while (SDL_WINDOW_IS_POPUP(toplevel)) { + toplevel = toplevel->parent; } - topmost->internal->keyboard_focus = window; - SDL_SetKeyboardFocus(window); + toplevel->internal->keyboard_focus = window; + + if (!window->is_hiding && !window->is_destroying) { + SDL_SetKeyboardFocus(window); + } } Uint32 X11_GetNetWMState(SDL_VideoDevice *_this, SDL_Window *window, Window xwindow) @@ -1533,7 +1536,7 @@ void X11_HideWindow(SDL_VideoDevice *_this, SDL_Window *window) SDL_Window *new_focus = window->parent; // Find the highest level window that isn't being hidden or destroyed. - while (new_focus->parent && (new_focus->is_hiding || new_focus->is_destroying)) { + while (SDL_WINDOW_IS_POPUP(new_focus) && (new_focus->is_hiding || new_focus->is_destroying)) { new_focus = new_focus->parent; }