From d602a8f1d4014e149dc9a06226b9adacfa557f3e Mon Sep 17 00:00:00 2001 From: Ritchie Cunningham Date: Sat, 4 Oct 2025 21:02:21 +0100 Subject: [PATCH] [Fix] Correct window event handling and Z-ordering. Resolves a bug where mouse clicks would "pass through" the top-most window and incorrectly trigger events on windows visually behind it. --- client/src/ui/desktop.cpp | 43 +++++++++++++++++++++++---------------- 1 file changed, 26 insertions(+), 17 deletions(-) diff --git a/client/src/ui/desktop.cpp b/client/src/ui/desktop.cpp index 2d3eeb3..22a526f 100644 --- a/client/src/ui/desktop.cpp +++ b/client/src/ui/desktop.cpp @@ -70,17 +70,32 @@ void Desktop::_set_focused_window(UIWindow* window) { return; } + /* Unfocus old window. */ if(_focused_window) { _focused_window->set_focused(false); } + /* Set new focused window. */ _focused_window = window; if(_focused_window) { _focused_window->set_focused(true); + + /* Move newly focused window to end of vector so it's rendered on top. */ + auto it = std::find_if(_windows.begin(), _windows.end(), + [window](const std::unique_ptr& p) { + return p.get() == window; + }); + if(it != _windows.end()) { + std::rotate(it, it+1, _windows.end()); + } } } void Desktop::handle_event(SDL_Event* event, int screen_width, int screen_height) { + /* Let focused window handle all events first. */ + if(_focused_window) { + _focused_window->handle_event(event, screen_width, screen_height, _taskbar->get_height()); + } if(event->type == SDL_EVENT_MOUSE_BUTTON_DOWN) { int mouse_x = event->button.x; int mouse_y = event->button.y; @@ -91,15 +106,20 @@ void Desktop::handle_event(SDL_Event* event, int screen_width, int screen_height return; } - /* Find the top-most window that was clicked. */ + /* If click no on focused window, find which window should receive focus. */ + bool click_on_window = false; for(int i = _windows.size()-1; i >= 0; --i) { if(_windows[i].get()->is_point_inside(mouse_x, mouse_y)) { if(!_windows[i]->is_minimized()) { _set_focused_window(_windows[i].get()); } + click_on_window = true; break; } } + if(!click_on_window) { + _set_focused_window(nullptr); + } } else if(event->type == SDL_EVENT_MOUSE_BUTTON_UP) { if(_taskbar->is_start_button_clicked(event, screen_height)) { _launcher_is_open = !_launcher_is_open; @@ -131,22 +151,14 @@ void Desktop::handle_event(SDL_Event* event, int screen_width, int screen_height } } } else if(event->type == SDL_EVENT_MOUSE_MOTION) { - bool on_resize_handle = false; - /* Iterate backwards since top-most windows are at the end. */ + /* Update cursor if hovering over any resize handle. */ for(int i = _windows.size() - 1; i >= 0; --i) { if(_windows[i]->is_mouse_over_resize_handle(event->motion.x, event->motion.y)) { - on_resize_handle = true; - break; + return CursorManager::set_cursor(CursorType::RESIZE_NWSE); } } - CursorManager::set_cursor(on_resize_handle ? CursorType::RESIZE_NWSE - : CursorType::ARROW); - } - - if(_focused_window) { - _focused_window->handle_event(event, screen_width, screen_height, - _taskbar->get_height()); + CursorManager::set_cursor(CursorType::ARROW); } } @@ -201,15 +213,12 @@ void Desktop::render(const RenderContext& context) { _render_wallpaper(context.ui_renderer); context.ui_renderer->flush_text(); - /* Pass 2: Windows (back to front). */ + /* Pass 2: Windows Render in order, last window is top-most. */ for(const auto& win : _windows) { - if(win.get() != _focused_window && !win->is_minimized()) { + if(!win->is_minimized()) { win.get()->render(context); } } - if(_focused_window && !_focused_window->is_minimized()) { - _focused_window->render(context); - } /* Pass 3: Top-level static UI (taskbar, Launcher, etc.). */ context.ui_renderer->begin_text();