Browse Source

LibGUI: Hook up GWindow event dispatch for paint and mouse events.

Andreas Kling 6 years ago
parent
commit
ea6678b7b3

+ 1 - 0
Kernel/GUITypes.h

@@ -76,6 +76,7 @@ struct GUI_Event {
         struct {
             GUI_Point position;
             GUI_MouseButton button;
+            unsigned buttons;
         } mouse;
         struct {
             char character;

+ 7 - 4
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 };
 };
 

+ 17 - 12
LibGUI/GEventLoop.cpp

@@ -9,6 +9,8 @@
 #include <LibC/sys/select.h>
 #include <LibC/gui.h>
 
+//#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<QueuedEvent> 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<QueuedEvent> 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<GEvent>&& 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<GMouseEvent>(type, event.mouse.position, button);
+    post_event(&window, make<GMouseEvent>(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:

+ 1 - 6
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<GPaintEvent&>(event));
     case GEvent::Show:
         return showEvent(static_cast<GShowEvent&>(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;

+ 2 - 2
LibGUI/GWidget.h

@@ -73,7 +73,7 @@ public:
         return m_window;
     }
 
-    void setWindow(GWindow*);
+    void set_window(GWindow*);
 
     GWidget* parentWidget() { return static_cast<GWidget*>(parent()); }
     const GWidget* parentWidget() const { return static_cast<const GWidget*>(parent()); }
@@ -84,7 +84,7 @@ public:
     const Font& font() const { return *m_font; }
     void setFont(RetainPtr<Font>&&);
 
-    virtual GraphicsBitmap* backing();
+    GraphicsBitmap* backing();
 
 private:
     GWindow* m_window { nullptr };

+ 37 - 2
LibGUI/GWindow.cpp

@@ -1,6 +1,7 @@
 #include "GWindow.h"
 #include "GEvent.h"
 #include "GEventLoop.h"
+#include "GWidget.h"
 #include <SharedGraphics/GraphicsBitmap.h>
 #include <LibC/gui.h>
 #include <LibC/stdio.h>
@@ -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, &params);
     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<GMouseEvent&>(event);
+        if (m_main_widget) {
+            auto result = m_main_widget->hitTest(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);
+            return result.widget->event(*local_event);
+        }
+    }
+
+    if (event.is_paint_event()) {
+        if (!m_main_widget)
+            return;
+        auto& paint_event = static_cast<GPaintEvent&>(event);
+        if (paint_event.rect().is_empty()) {
+            m_main_widget->paintEvent(*make<GPaintEvent>(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<GPaintEvent>());
 }
 
 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();
 }

+ 1 - 0
SharedGraphics/Painter.cpp

@@ -6,6 +6,7 @@
 
 #ifdef LIBGUI
 #include <LibGUI/GWidget.h>
+#include <LibGUI/GWindow.h>
 #endif
 
 #define DEBUG_WIDGET_UNDERDRAW

+ 1 - 2
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();
 }
 

+ 5 - 2
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<MouseEvent&>(event).position();
         gui_event.mouse.button = GUI_MouseButton::NoButton;
+        gui_event.mouse.buttons = static_cast<MouseEvent&>(event).buttons();
         break;
     case WSEvent::MouseDown:
         gui_event.type = GUI_Event::Type::MouseDown;
         gui_event.mouse.position = static_cast<MouseEvent&>(event).position();
         gui_event.mouse.button = to_api(static_cast<MouseEvent&>(event).button());
+        gui_event.mouse.buttons = static_cast<MouseEvent&>(event).buttons();
         break;
     case WSEvent::MouseUp:
         gui_event.type = GUI_Event::Type::MouseUp;
         gui_event.mouse.position = static_cast<MouseEvent&>(event).position();
         gui_event.mouse.button = to_api(static_cast<MouseEvent&>(event).button());
+        gui_event.mouse.buttons = static_cast<MouseEvent&>(event).buttons();
         break;
     case WSEvent::KeyDown:
         gui_event.type = GUI_Event::Type::KeyDown;