[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.
This commit is contained in:
Ritchie Cunningham 2025-10-04 21:02:21 +01:00
parent 69eee6da8f
commit d602a8f1d4

View File

@ -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<UIWindow>& 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();