diff --git a/Kernel/GUITypes.h b/Kernel/GUITypes.h index 9b22ee7e18..3b25fe0a08 100644 --- a/Kernel/GUITypes.h +++ b/Kernel/GUITypes.h @@ -76,6 +76,7 @@ struct GUI_Event { struct { GUI_Point position; GUI_MouseButton button; + unsigned buttons; } mouse; struct { char character; diff --git a/LibGUI/GEvent.h b/LibGUI/GEvent.h index 0468a6c772..e02aca777c 100644 --- a/LibGUI/GEvent.h +++ b/LibGUI/GEvent.h @@ -47,9 +47,9 @@ public: const char* name() const { return eventNames[(unsigned)m_type]; } - bool isMouseEvent() const { return m_type == MouseMove || m_type == MouseDown || m_type == MouseUp; } - bool isKeyEvent() const { return m_type == KeyUp || m_type == KeyDown; } - bool isPaintEvent() const { return m_type == Paint; } + bool is_mouse_event() const { return m_type == MouseMove || m_type == MouseDown || m_type == MouseUp; } + bool is_key_event() const { return m_type == KeyUp || m_type == KeyDown; } + bool is_paint_event() const { return m_type == Paint; } private: Type m_type { Invalid }; @@ -134,9 +134,10 @@ private: class GMouseEvent final : public GEvent { public: - GMouseEvent(Type type, const Point& position, GMouseButton button = GMouseButton::None) + GMouseEvent(Type type, const Point& position, unsigned buttons, GMouseButton button = GMouseButton::None) : GEvent(type) , m_position(position) + , m_buttons(buttons) , m_button(button) { } @@ -145,9 +146,11 @@ public: int x() const { return m_position.x(); } int y() const { return m_position.y(); } GMouseButton button() const { return m_button; } + unsigned buttons() const { return m_buttons; } private: Point m_position; + unsigned m_buttons { 0 }; GMouseButton m_button { GMouseButton::None }; }; diff --git a/LibGUI/GEventLoop.cpp b/LibGUI/GEventLoop.cpp index 84fd81ce85..d9b1abc6d6 100644 --- a/LibGUI/GEventLoop.cpp +++ b/LibGUI/GEventLoop.cpp @@ -9,6 +9,8 @@ #include #include +//#define GEVENTLOOP_DEBUG + static GEventLoop* s_mainGEventLoop; void GEventLoop::initialize() @@ -34,7 +36,7 @@ GEventLoop& GEventLoop::main() int GEventLoop::exec() { - m_event_fd = open("/dev/gui_events", O_RDONLY); + m_event_fd = open("/dev/gui_events", O_RDONLY | O_NONBLOCK); if (m_event_fd < 0) { perror("GEventLoop::exec(): open"); exit(1); @@ -44,14 +46,13 @@ int GEventLoop::exec() for (;;) { if (m_queued_events.is_empty()) wait_for_event(); - Vector events; - { - events = move(m_queued_events); - } - for (auto& queuedEvent : events) { - auto* receiver = queuedEvent.receiver; - auto& event = *queuedEvent.event; - //printf("GEventLoop: GObject{%p} event %u (%s)\n", receiver, (unsigned)event.type(), event.name()); + Vector events = move(m_queued_events); + for (auto& queued_event : events) { + auto* receiver = queued_event.receiver; + auto& event = *queued_event.event; +#ifdef GEVENTLOOP_DEBUG + dbgprintf("GEventLoop: GObject{%p} event %u (%s)\n", receiver, (unsigned)event.type(), event.name()); +#endif if (!receiver) { switch (event.type()) { case GEvent::Quit: @@ -71,7 +72,9 @@ int GEventLoop::exec() void GEventLoop::post_event(GObject* receiver, OwnPtr&& event) { - //printf("GEventLoop::postGEvent: {%u} << receiver=%p, event=%p\n", m_queuedEvents.size(), receiver, event.ptr()); +#ifdef GEVENTLOOP_DEBUG + dbgprintf("GEventLoop::post_event: {%u} << receiver=%p, event=%p\n", m_queued_events.size(), receiver, event.ptr()); +#endif m_queued_events.append({ receiver, move(event) }); } @@ -97,7 +100,7 @@ void GEventLoop::handle_mouse_event(const GUI_Event& event, GWindow& window) case GUI_MouseButton::Middle: button = GMouseButton::Middle; break; default: ASSERT_NOT_REACHED(); break; } - auto mouse_event = make(type, event.mouse.position, button); + post_event(&window, make(type, event.mouse.position, event.mouse.buttons, button)); } void GEventLoop::wait_for_event() @@ -105,7 +108,8 @@ void GEventLoop::wait_for_event() fd_set rfds; FD_ZERO(&rfds); FD_SET(m_event_fd, &rfds); - int rc = select(m_event_fd + 1, &rfds, nullptr, nullptr, nullptr); + struct timeval timeout = { 0, 0 }; + int rc = select(m_event_fd + 1, &rfds, nullptr, nullptr, m_queued_events.is_empty() ? nullptr : &timeout); if (rc < 0) { ASSERT_NOT_REACHED(); } @@ -126,6 +130,7 @@ void GEventLoop::wait_for_event() auto* window = GWindow::from_window_id(event.window_id); if (!window) { dbgprintf("GEventLoop received event for invalid window ID %d\n", event.window_id); + continue; } switch (event.type) { case GUI_Event::Type::Paint: diff --git a/LibGUI/GWidget.cpp b/LibGUI/GWidget.cpp index c959dc7858..62caf4cc7f 100644 --- a/LibGUI/GWidget.cpp +++ b/LibGUI/GWidget.cpp @@ -36,10 +36,6 @@ void GWidget::event(GEvent& event) switch (event.type()) { case GEvent::Paint: m_hasPendingPaintEvent = false; - if (auto* win = window()) { - if (!win->is_visible()) - return; - } return paintEvent(static_cast(event)); case GEvent::Show: return showEvent(static_cast(event)); @@ -63,7 +59,6 @@ void GWidget::event(GEvent& event) void GWidget::paintEvent(GPaintEvent& event) { - //printf("GWidget::paintEvent :)\n"); if (fillWithBackgroundColor()) { Painter painter(*this); painter.fill_rect(rect(), backgroundColor()); @@ -125,7 +120,7 @@ GWidget::HitTestResult GWidget::hitTest(int x, int y) return { this, x, y }; } -void GWidget::setWindow(GWindow* window) +void GWidget::set_window(GWindow* window) { if (m_window == window) return; diff --git a/LibGUI/GWidget.h b/LibGUI/GWidget.h index adfa9397e4..ee02ce50b8 100644 --- a/LibGUI/GWidget.h +++ b/LibGUI/GWidget.h @@ -73,7 +73,7 @@ public: return m_window; } - void setWindow(GWindow*); + void set_window(GWindow*); GWidget* parentWidget() { return static_cast(parent()); } const GWidget* parentWidget() const { return static_cast(parent()); } @@ -84,7 +84,7 @@ public: const Font& font() const { return *m_font; } void setFont(RetainPtr&&); - virtual GraphicsBitmap* backing(); + GraphicsBitmap* backing(); private: GWindow* m_window { nullptr }; diff --git a/LibGUI/GWindow.cpp b/LibGUI/GWindow.cpp index 9a7ca2a307..93d2dd9c54 100644 --- a/LibGUI/GWindow.cpp +++ b/LibGUI/GWindow.cpp @@ -1,6 +1,7 @@ #include "GWindow.h" #include "GEvent.h" #include "GEventLoop.h" +#include "GWidget.h" #include #include #include @@ -43,7 +44,6 @@ GWindow::GWindow(GObject* parent) perror("gui_get_window_backing_store"); exit(1); } - m_backing = GraphicsBitmap::create_wrapper(backing.size, backing.pixels); windows().set(m_window_id, this); @@ -75,10 +75,43 @@ void GWindow::set_rect(const Rect& rect) rc = gui_set_window_parameters(m_window_id, ¶ms); ASSERT(rc == 0); m_rect = rect; + GUI_WindowBackingStoreInfo backing; + rc = gui_get_window_backing_store(m_window_id, &backing); + if (rc < 0) { + perror("gui_get_window_backing_store"); + exit(1); + } + m_backing = GraphicsBitmap::create_wrapper(backing.size, backing.pixels); } void GWindow::event(GEvent& event) { + if (event.is_mouse_event()) { + if (!m_main_widget) + return; + auto& mouse_event = static_cast(event); + if (m_main_widget) { + auto result = m_main_widget->hitTest(mouse_event.x(), mouse_event.y()); + auto local_event = make(event.type(), Point { result.localX, result.localY }, mouse_event.buttons(), mouse_event.button()); + ASSERT(result.widget); + return result.widget->event(*local_event); + } + } + + if (event.is_paint_event()) { + if (!m_main_widget) + return; + auto& paint_event = static_cast(event); + if (paint_event.rect().is_empty()) { + m_main_widget->paintEvent(*make(m_main_widget->rect())); + } else { + m_main_widget->event(event); + } + int rc = gui_invalidate_window(m_window_id, nullptr); + ASSERT(rc == 0); + } + + return GObject::event(event); } bool GWindow::is_visible() const @@ -96,7 +129,7 @@ void GWindow::show() void GWindow::update() { - gui_invalidate_window(m_window_id, nullptr); + GEventLoop::main().post_event(this, make()); } void GWindow::set_main_widget(GWidget* widget) @@ -104,5 +137,7 @@ void GWindow::set_main_widget(GWidget* widget) if (m_main_widget == widget) return; m_main_widget = widget; + if (widget) + widget->set_window(this); update(); } diff --git a/SharedGraphics/Painter.cpp b/SharedGraphics/Painter.cpp index d8e9400601..48e52f245b 100644 --- a/SharedGraphics/Painter.cpp +++ b/SharedGraphics/Painter.cpp @@ -6,6 +6,7 @@ #ifdef LIBGUI #include +#include #endif #define DEBUG_WIDGET_UNDERDRAW diff --git a/Userland/guitest2.cpp b/Userland/guitest2.cpp index 850dd5abd8..ecc9b09166 100644 --- a/Userland/guitest2.cpp +++ b/Userland/guitest2.cpp @@ -17,10 +17,9 @@ static GWindow* make_font_test_window(); int main(int argc, char** argv) { + GEventLoop loop; auto* window = make_font_test_window(); window->show(); - - GEventLoop loop; return loop.exec(); } diff --git a/WindowServer/WSWindow.cpp b/WindowServer/WSWindow.cpp index b1d7bd8774..d2bb7f5177 100644 --- a/WindowServer/WSWindow.cpp +++ b/WindowServer/WSWindow.cpp @@ -29,10 +29,10 @@ void WSWindow::set_rect(const Rect& rect) { if (m_rect == rect) return; - auto oldRect = m_rect; + auto old_rect = m_rect; m_rect = rect; m_backing = GraphicsBitmap::create(m_process, m_rect.size()); - WSWindowManager::the().notify_rect_changed(*this, oldRect, m_rect); + WSWindowManager::the().notify_rect_changed(*this, old_rect, m_rect); } // FIXME: Just use the same types. @@ -60,16 +60,19 @@ void WSWindow::event(WSEvent& event) gui_event.type = GUI_Event::Type::MouseMove; gui_event.mouse.position = static_cast(event).position(); gui_event.mouse.button = GUI_MouseButton::NoButton; + gui_event.mouse.buttons = static_cast(event).buttons(); break; case WSEvent::MouseDown: gui_event.type = GUI_Event::Type::MouseDown; gui_event.mouse.position = static_cast(event).position(); gui_event.mouse.button = to_api(static_cast(event).button()); + gui_event.mouse.buttons = static_cast(event).buttons(); break; case WSEvent::MouseUp: gui_event.type = GUI_Event::Type::MouseUp; gui_event.mouse.position = static_cast(event).position(); gui_event.mouse.button = to_api(static_cast(event).button()); + gui_event.mouse.buttons = static_cast(event).buttons(); break; case WSEvent::KeyDown: gui_event.type = GUI_Event::Type::KeyDown;