mirror of
https://github.com/RGBCube/serenity
synced 2025-05-31 10:38:11 +00:00
WindowServer: Re-evaluate the mouse cursor when alpha hit-testing
A window repaint may change the alpha value, resulting in a different hit test outcome. In those cases, re-evaluate the cursor hit testing after a window was painted, and update the cursor if needed.
This commit is contained in:
parent
bd830c2dfe
commit
2d29bfc89e
4 changed files with 60 additions and 5 deletions
|
@ -1043,6 +1043,52 @@ void WindowManager::process_mouse_event(MouseEvent& event, Window*& hovered_wind
|
|||
clear_resize_candidate();
|
||||
}
|
||||
|
||||
void WindowManager::reevaluate_hovered_window(Window* updated_window)
|
||||
{
|
||||
if (m_dnd_client || m_resize_window || m_move_window || m_cursor_tracking_button || MenuManager::the().has_open_menu())
|
||||
return;
|
||||
|
||||
auto cursor_location = Screen::the().cursor_location();
|
||||
auto* currently_hovered = hovered_window();
|
||||
if (updated_window) {
|
||||
if (!(updated_window == currently_hovered || updated_window->frame().rect().contains(cursor_location) || (currently_hovered && currently_hovered->frame().rect().contains(cursor_location))))
|
||||
return;
|
||||
}
|
||||
|
||||
Window* hovered_window = nullptr;
|
||||
if (auto* fullscreen_window = active_fullscreen_window()) {
|
||||
if (fullscreen_window->hit_test(cursor_location))
|
||||
hovered_window = fullscreen_window;
|
||||
} else {
|
||||
for_each_visible_window_from_front_to_back([&](Window& window) {
|
||||
if (!window.hit_test(cursor_location))
|
||||
return IterationDecision::Continue;
|
||||
hovered_window = &window;
|
||||
return IterationDecision::Break;
|
||||
});
|
||||
}
|
||||
|
||||
if (set_hovered_window(hovered_window)) {
|
||||
if (currently_hovered && m_resize_candidate == currently_hovered)
|
||||
clear_resize_candidate();
|
||||
|
||||
if (hovered_window) {
|
||||
// Send a fake MouseMove event. This allows the new hovering window
|
||||
// to determine which widget we're hovering, and also update the cursor
|
||||
// accordingly. We do this because this re-evaluation of the currently
|
||||
// hovered window wasn't triggered by a mouse move event, but rather
|
||||
// e.g. a hit-test result change due to a transparent window repaint.
|
||||
if (hovered_window->hit_test(cursor_location, false)) {
|
||||
MouseEvent event(Event::MouseMove, cursor_location.translated(-hovered_window->rect().location()), 0, MouseButton::None, 0);
|
||||
hovered_window->event(event);
|
||||
} else if (!hovered_window->is_frameless()) {
|
||||
MouseEvent event(Event::MouseMove, cursor_location.translated(-hovered_window->frame().rect().location()), 0, MouseButton::None, 0);
|
||||
hovered_window->frame().on_mouse_event(event);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void WindowManager::clear_resize_candidate()
|
||||
{
|
||||
if (m_resize_candidate)
|
||||
|
@ -1315,10 +1361,10 @@ void WindowManager::set_active_window(Window* window, bool make_input)
|
|||
Compositor::the().invalidate_occlusions();
|
||||
}
|
||||
|
||||
void WindowManager::set_hovered_window(Window* window)
|
||||
bool WindowManager::set_hovered_window(Window* window)
|
||||
{
|
||||
if (m_hovered_window == window)
|
||||
return;
|
||||
return false;
|
||||
|
||||
if (m_hovered_window)
|
||||
Core::EventLoop::current().post_event(*m_hovered_window, make<Event>(Event::WindowLeft));
|
||||
|
@ -1327,6 +1373,7 @@ void WindowManager::set_hovered_window(Window* window)
|
|||
|
||||
if (m_hovered_window)
|
||||
Core::EventLoop::current().post_event(*m_hovered_window, make<Event>(Event::WindowEntered));
|
||||
return true;
|
||||
}
|
||||
|
||||
const ClientConnection* WindowManager::active_client() const
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue