1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-27 06:17:35 +00:00

LibGUI: Implement enter/leave events (with WindowServer support.)

Windows now learn when the mouse cursor leaves or enters them.
Use this to implement GWidget::{enter,leave}_event() and use that
to implement the CoolBar button effect. :^)
This commit is contained in:
Andreas Kling 2019-02-20 10:12:19 +01:00
parent af7eb5c89c
commit bf30502560
14 changed files with 103 additions and 5 deletions

View file

@ -89,3 +89,14 @@ void GButton::mouseup_event(GMouseEvent& event)
GWidget::mouseup_event(event);
}
void GButton::enter_event(GEvent&)
{
m_hovered = true;
update();
}
void GButton::leave_event(GEvent&)
{
m_hovered = false;
update();
}

View file

@ -28,6 +28,8 @@ private:
virtual void mousedown_event(GMouseEvent&) override;
virtual void mouseup_event(GMouseEvent&) override;
virtual void mousemove_event(GMouseEvent&) override;
virtual void enter_event(GEvent&) override;
virtual void leave_event(GEvent&) override;
virtual const char* class_name() const override { return "GButton"; }

View file

@ -17,10 +17,14 @@ public:
MouseMove,
MouseDown,
MouseUp,
Enter,
Leave,
KeyDown,
KeyUp,
Timer,
DeferredDestroy,
WindowEntered,
WindowLeft,
WindowBecameInactive,
WindowBecameActive,
FocusIn,

View file

@ -134,6 +134,11 @@ void GEventLoop::handle_window_close_request_event(const WSAPI_ServerMessage&, G
post_event(&window, make<GEvent>(GEvent::WindowCloseRequest));
}
void GEventLoop::handle_window_entered_or_left_event(const WSAPI_ServerMessage& message, GWindow& window)
{
post_event(&window, make<GEvent>(message.type == WSAPI_ServerMessage::Type::WindowEntered ? GEvent::WindowEntered : GEvent::WindowLeft));
}
void GEventLoop::handle_key_event(const WSAPI_ServerMessage& event, GWindow& window)
{
#ifdef GEVENTLOOP_DEBUG
@ -294,6 +299,10 @@ void GEventLoop::wait_for_event()
case WSAPI_ServerMessage::Type::KeyUp:
handle_key_event(event, *window);
break;
case WSAPI_ServerMessage::Type::WindowEntered:
case WSAPI_ServerMessage::Type::WindowLeft:
handle_window_entered_or_left_event(event, *window);
break;
default:
break;
}

View file

@ -48,6 +48,7 @@ private:
void handle_window_activation_event(const WSAPI_ServerMessage&, GWindow&);
void handle_window_close_request_event(const WSAPI_ServerMessage&, GWindow&);
void handle_menu_event(const WSAPI_ServerMessage&);
void handle_window_entered_or_left_event(const WSAPI_ServerMessage&, GWindow&);
void get_next_timer_expiration(timeval&);
struct QueuedEvent {

View file

@ -63,6 +63,10 @@ void GWidget::event(GEvent& event)
return mousedown_event(static_cast<GMouseEvent&>(event));
case GEvent::MouseUp:
return mouseup_event(static_cast<GMouseEvent&>(event));
case GEvent::Enter:
return enter_event(event);
case GEvent::Leave:
return leave_event(event);
default:
return GObject::event(event);
}
@ -173,6 +177,14 @@ void GWidget::focusout_event(GEvent&)
{
}
void GWidget::enter_event(GEvent&)
{
}
void GWidget::leave_event(GEvent&)
{
}
void GWidget::update()
{
update(rect());

View file

@ -43,6 +43,8 @@ public:
virtual void mouseup_event(GMouseEvent&);
virtual void focusin_event(GEvent&);
virtual void focusout_event(GEvent&);
virtual void enter_event(GEvent&);
virtual void leave_event(GEvent&);
Rect relative_rect() const { return m_relative_rect; }
Point relative_position() const { return m_relative_rect.location(); }

View file

@ -157,6 +157,7 @@ void GWindow::event(GEvent& event)
auto result = m_main_widget->hit_test(mouse_event.x(), mouse_event.y());
auto local_event = make<GMouseEvent>(event.type(), Point { result.localX, result.localY }, mouse_event.buttons(), mouse_event.button());
ASSERT(result.widget);
set_hovered_widget(result.widget);
return result.widget->event(*local_event);
}
return;
@ -203,6 +204,11 @@ void GWindow::event(GEvent& event)
return;
}
if (event.type() == GEvent::WindowLeft) {
set_hovered_widget(nullptr);
return;
}
GObject::event(event);
}
@ -301,3 +307,17 @@ void GWindow::set_opacity(float opacity)
m_opacity_when_windowless = opacity;
GEventLoop::main().post_message_to_server(request);
}
void GWindow::set_hovered_widget(GWidget* widget)
{
if (widget == m_hovered_widget.ptr())
return;
if (m_hovered_widget)
GEventLoop::main().post_event(m_hovered_widget.ptr(), make<GEvent>(GEvent::Leave));
m_hovered_widget = widget ? widget->make_weak_ptr() : nullptr;
if (m_hovered_widget)
GEventLoop::main().post_event(m_hovered_widget.ptr(), make<GEvent>(GEvent::Enter));
}

View file

@ -64,6 +64,10 @@ public:
bool should_exit_app_on_close() const { return m_should_exit_app_on_close; }
void set_should_exit_app_on_close(bool b) { m_should_exit_app_on_close = b; }
GWidget* hovered_widget() { return m_hovered_widget.ptr(); }
const GWidget* hovered_widget() const { return m_hovered_widget.ptr(); }
void set_hovered_widget(GWidget*);
private:
virtual const char* class_name() const override { return "GWindow"; }
@ -73,6 +77,7 @@ private:
GWidget* m_main_widget { nullptr };
GWidget* m_focused_widget { nullptr };
WeakPtr<GWidget> m_global_cursor_tracking_widget;
WeakPtr<GWidget> m_hovered_widget;
Rect m_rect_when_windowless;
String m_title_when_windowless;
Vector<Rect> m_pending_paint_event_rects;