Browse Source

Start bringing up LibGUI properly (formerly Widgets.)

Andreas Kling 6 years ago
parent
commit
8eae89a405

+ 1 - 0
Kernel/init.cpp

@@ -104,6 +104,7 @@ static void init_stage2()
     Process::create_user_process("/bin/Terminal", (uid_t)100, (gid_t)100, (pid_t)0, error, { }, move(environment), tty0);
     Process::create_user_process("/bin/Terminal", (uid_t)100, (gid_t)100, (pid_t)0, error, { }, move(environment), tty0);
 #ifdef SPAWN_GUI_TEST_APP
 #ifdef SPAWN_GUI_TEST_APP
     Process::create_user_process("/bin/guitest", (uid_t)100, (gid_t)100, (pid_t)0, error, { }, move(environment), tty0);
     Process::create_user_process("/bin/guitest", (uid_t)100, (gid_t)100, (pid_t)0, error, { }, move(environment), tty0);
+    Process::create_user_process("/bin/guitest2", (uid_t)100, (gid_t)100, (pid_t)0, error, { }, move(environment), tty0);
 #endif
 #endif
 #ifdef SPAWN_MULTIPLE_SHELLS
 #ifdef SPAWN_MULTIPLE_SHELLS
     Process::create_user_process("/bin/sh", (uid_t)100, (gid_t)100, (pid_t)0, error, { }, { }, tty1);
     Process::create_user_process("/bin/sh", (uid_t)100, (gid_t)100, (pid_t)0, error, { }, { }, tty1);

+ 4 - 0
Kernel/makeuserland.sh

@@ -4,6 +4,10 @@ sudo id
 
 
 make -C ../LibC clean && \
 make -C ../LibC clean && \
 make -C ../LibC && \
 make -C ../LibC && \
+make -C ../LibGUI clean && \
+make -C ../LibGUI && \
+make -C ../Terminal clean && \
+make -C ../Terminal && \
 make -C ../Userland clean && \
 make -C ../Userland clean && \
 make -C ../Userland && \
 make -C ../Userland && \
 sudo ./sync.sh
 sudo ./sync.sh

+ 1 - 0
Kernel/sync.sh

@@ -43,6 +43,7 @@ cp -v ../Userland/touch mnt/bin/touch
 cp -v ../Userland/sync mnt/bin/sync
 cp -v ../Userland/sync mnt/bin/sync
 cp -v ../Userland/more mnt/bin/more
 cp -v ../Userland/more mnt/bin/more
 cp -v ../Userland/guitest mnt/bin/guitest
 cp -v ../Userland/guitest mnt/bin/guitest
+cp -v ../Userland/guitest2 mnt/bin/guitest2
 cp -v ../Userland/sysctl mnt/bin/sysctl
 cp -v ../Userland/sysctl mnt/bin/sysctl
 cp -v ../Terminal/Terminal mnt/bin/Terminal
 cp -v ../Terminal/Terminal mnt/bin/Terminal
 sh sync-local.sh
 sh sync-local.sh

+ 2 - 2
LibGUI/GEvent.h

@@ -134,9 +134,9 @@ private:
 
 
 class GMouseEvent final : public GEvent {
 class GMouseEvent final : public GEvent {
 public:
 public:
-    GMouseEvent(Type type, int x, int y, GMouseButton button = GMouseButton::None)
+    GMouseEvent(Type type, const Point& position, GMouseButton button = GMouseButton::None)
         : GEvent(type)
         : GEvent(type)
-        , m_position(x, y)
+        , m_position(position)
         , m_button(button)
         , m_button(button)
     {
     {
     }
     }

+ 88 - 6
LibGUI/GEventLoop.cpp

@@ -1,6 +1,13 @@
 #include "GEventLoop.h"
 #include "GEventLoop.h"
 #include "GEvent.h"
 #include "GEvent.h"
 #include "GObject.h"
 #include "GObject.h"
+#include "GWindow.h"
+#include <LibC/unistd.h>
+#include <LibC/stdio.h>
+#include <LibC/fcntl.h>
+#include <LibC/string.h>
+#include <LibC/sys/select.h>
+#include <LibC/gui.h>
 
 
 static GEventLoop* s_mainGEventLoop;
 static GEventLoop* s_mainGEventLoop;
 
 
@@ -27,13 +34,19 @@ GEventLoop& GEventLoop::main()
 
 
 int GEventLoop::exec()
 int GEventLoop::exec()
 {
 {
+    m_event_fd = open("/dev/gui_events", O_RDONLY);
+    if (m_event_fd < 0) {
+        perror("GEventLoop::exec(): open");
+        exit(1);
+    }
+
     m_running = true;
     m_running = true;
     for (;;) {
     for (;;) {
-        if (m_queuedEvents.is_empty())
-            waitForEvent();
+        if (m_queued_events.is_empty())
+            wait_for_event();
         Vector<QueuedEvent> events;
         Vector<QueuedEvent> events;
         {
         {
-            events = move(m_queuedEvents);
+            events = move(m_queued_events);
         }
         }
         for (auto& queuedEvent : events) {
         for (auto& queuedEvent : events) {
             auto* receiver = queuedEvent.receiver;
             auto* receiver = queuedEvent.receiver;
@@ -56,12 +69,81 @@ int GEventLoop::exec()
     }
     }
 }
 }
 
 
-void GEventLoop::postEvent(GObject* receiver, OwnPtr<GEvent>&& event)
+void GEventLoop::post_event(GObject* receiver, OwnPtr<GEvent>&& event)
 {
 {
     //printf("GEventLoop::postGEvent: {%u} << receiver=%p, event=%p\n", m_queuedEvents.size(), receiver, event.ptr());
     //printf("GEventLoop::postGEvent: {%u} << receiver=%p, event=%p\n", m_queuedEvents.size(), receiver, event.ptr());
-    m_queuedEvents.append({ receiver, move(event) });
+    m_queued_events.append({ receiver, move(event) });
+}
+
+void GEventLoop::handle_paint_event(const GUI_Event& event, GWindow& window)
+{
+    post_event(&window, make<GPaintEvent>(event.paint.rect));
+}
+
+void GEventLoop::handle_mouse_event(const GUI_Event& event, GWindow& window)
+{
+    GMouseEvent::Type type;
+    switch (event.type) {
+    case GUI_Event::Type::MouseMove: type = GEvent::MouseMove; break;
+    case GUI_Event::Type::MouseUp: type = GEvent::MouseUp; break;
+    case GUI_Event::Type::MouseDown: type = GEvent::MouseDown; break;
+    default: ASSERT_NOT_REACHED(); break;
+    }
+    GMouseButton button { GMouseButton::None };
+    switch (event.mouse.button) {
+    case GUI_MouseButton::NoButton: button = GMouseButton::None; break;
+    case GUI_MouseButton::Left: button = GMouseButton::Left; break;
+    case GUI_MouseButton::Right: button = GMouseButton::Right; break;
+    case GUI_MouseButton::Middle: button = GMouseButton::Middle; break;
+    default: ASSERT_NOT_REACHED(); break;
+    }
+    auto mouse_event = make<GMouseEvent>(type, event.mouse.position, button);
 }
 }
 
 
-void GEventLoop::waitForEvent()
+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);
+    if (rc < 0) {
+        ASSERT_NOT_REACHED();
+    }
+
+    if (!FD_ISSET(m_event_fd, &rfds))
+        return;
+
+    for (;;) {
+        GUI_Event event;
+        ssize_t nread = read(m_event_fd, &event, sizeof(GUI_Event));
+        if (nread < 0) {
+            perror("read");
+            exit(1); // FIXME: This should cause EventLoop::exec() to return 1.
+        }
+        if (nread == 0)
+            break;
+        assert(nread == sizeof(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);
+        }
+        switch (event.type) {
+        case GUI_Event::Type::Paint:
+            dbgprintf("WID=%x Paint [%d,%d %dx%d]\n", event.window_id, event.paint.rect.location.x, event.paint.rect.location.y, event.paint.rect.size.width, event.paint.rect.size.height); break;
+            handle_paint_event(event, *window);
+            break;
+        case GUI_Event::Type::MouseDown:
+        case GUI_Event::Type::MouseUp:
+        case GUI_Event::Type::MouseMove:
+            dbgprintf("WID=%x MouseEvent %d,%d\n", event.window_id, event.mouse.position.x, event.mouse.position.y);
+            handle_mouse_event(event, *window);
+            break;
+        case GUI_Event::Type::WindowActivated:
+            dbgprintf("WID=%x WindowActivated\n", event.window_id);
+            break;
+        case GUI_Event::Type::WindowDeactivated:
+            dbgprintf("WID=%x WindowDeactivated\n", event.window_id);
+            break;
+        }
+    }
 }
 }

+ 8 - 3
LibGUI/GEventLoop.h

@@ -5,6 +5,8 @@
 #include <AK/Vector.h>
 #include <AK/Vector.h>
 
 
 class GObject;
 class GObject;
+class GWindow;
+struct GUI_Event;
 
 
 class GEventLoop {
 class GEventLoop {
 public:
 public:
@@ -13,7 +15,7 @@ public:
 
 
     int exec();
     int exec();
 
 
-    void postEvent(GObject* receiver, OwnPtr<GEvent>&&);
+    void post_event(GObject* receiver, OwnPtr<GEvent>&&);
 
 
     static GEventLoop& main();
     static GEventLoop& main();
 
 
@@ -22,13 +24,16 @@ public:
     bool running() const { return m_running; }
     bool running() const { return m_running; }
 
 
 private:
 private:
-    void waitForEvent();
+    void wait_for_event();
+    void handle_paint_event(const GUI_Event&, GWindow&);
+    void handle_mouse_event(const GUI_Event&, GWindow&);
 
 
     struct QueuedEvent {
     struct QueuedEvent {
         GObject* receiver { nullptr };
         GObject* receiver { nullptr };
         OwnPtr<GEvent> event;
         OwnPtr<GEvent> event;
     };
     };
-    Vector<QueuedEvent> m_queuedEvents;
+    Vector<QueuedEvent> m_queued_events;
 
 
+    int m_event_fd { -1 };
     bool m_running { false };
     bool m_running { false };
 };
 };

+ 1 - 1
LibGUI/GObject.cpp

@@ -71,6 +71,6 @@ void GObject::stopTimer()
 
 
 void GObject::deleteLater()
 void GObject::deleteLater()
 {
 {
-    GEventLoop::main().postEvent(this, make<GEvent>(GEvent::DeferredDestroy));
+    GEventLoop::main().post_event(this, make<GEvent>(GEvent::DeferredDestroy));
 }
 }
 
 

+ 1 - 3
LibGUI/GWidget.cpp

@@ -37,8 +37,6 @@ void GWidget::event(GEvent& event)
     case GEvent::Paint:
     case GEvent::Paint:
         m_hasPendingPaintEvent = false;
         m_hasPendingPaintEvent = false;
         if (auto* win = window()) {
         if (auto* win = window()) {
-            if (win->is_being_dragged())
-                return;
             if (!win->is_visible())
             if (!win->is_visible())
                 return;
                 return;
         }
         }
@@ -112,7 +110,7 @@ void GWidget::update()
     if (m_hasPendingPaintEvent)
     if (m_hasPendingPaintEvent)
         return;
         return;
     m_hasPendingPaintEvent = true;
     m_hasPendingPaintEvent = true;
-    GEventLoop::main().postEvent(w, make<GPaintEvent>(relativeRect()));
+    GEventLoop::main().post_event(w, make<GPaintEvent>(relativeRect()));
 }
 }
 
 
 GWidget::HitTestResult GWidget::hitTest(int x, int y)
 GWidget::HitTestResult GWidget::hitTest(int x, int y)

+ 59 - 2
LibGUI/GWindow.cpp

@@ -2,10 +2,51 @@
 #include "GEvent.h"
 #include "GEvent.h"
 #include "GEventLoop.h"
 #include "GEventLoop.h"
 #include <SharedGraphics/GraphicsBitmap.h>
 #include <SharedGraphics/GraphicsBitmap.h>
+#include <LibC/gui.h>
+#include <LibC/stdio.h>
+#include <LibC/stdlib.h>
+#include <AK/HashMap.h>
 
 
-GWindow::GWindow(int window_id)
-    : m_window_id(window_id)
+static HashMap<int, GWindow*>* s_windows;
+
+static HashMap<int, GWindow*>& windows()
+{
+    if (!s_windows)
+        s_windows = new HashMap<int, GWindow*>;
+    return *s_windows;
+}
+
+GWindow* GWindow::from_window_id(int window_id)
+{
+    auto it = windows().find(window_id);
+    if (it != windows().end())
+        return (*it).value;
+    return nullptr;
+}
+
+GWindow::GWindow(GObject* parent)
+    : GObject(parent)
 {
 {
+    GUI_CreateWindowParameters wparams;
+    wparams.rect = { { 100, 400 }, { 140, 140 } };
+    wparams.background_color = 0xffc0c0;
+    strcpy(wparams.title, "GWindow");
+    m_window_id = gui_create_window(&wparams);
+    if (m_window_id < 0) {
+        perror("gui_create_window");
+        exit(1);
+    }
+
+    GUI_WindowBackingStoreInfo backing;
+    int 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);
+
+    windows().set(m_window_id, this);
 }
 }
 
 
 GWindow::~GWindow()
 GWindow::~GWindow()
@@ -40,3 +81,19 @@ void GWindow::close()
 {
 {
 }
 }
 
 
+void GWindow::show()
+{
+}
+
+void GWindow::update()
+{
+    gui_invalidate_window(m_window_id, nullptr);
+}
+
+void GWindow::set_main_widget(GWidget* widget)
+{
+    if (m_main_widget == widget)
+        return;
+    m_main_widget = widget;
+    update();
+}

+ 12 - 5
LibGUI/GWindow.h

@@ -5,11 +5,15 @@
 #include <SharedGraphics/GraphicsBitmap.h>
 #include <SharedGraphics/GraphicsBitmap.h>
 #include <AK/AKString.h>
 #include <AK/AKString.h>
 
 
+class GWidget;
+
 class GWindow final : public GObject {
 class GWindow final : public GObject {
 public:
 public:
-    explicit GWindow(int window_id);
+    GWindow(GObject* parent = nullptr);
     virtual ~GWindow() override;
     virtual ~GWindow() override;
 
 
+    static GWindow* from_window_id(int);
+
     int window_id() const { return m_window_id; }
     int window_id() const { return m_window_id; }
 
 
     String title() const { return m_title; }
     String title() const { return m_title; }
@@ -29,21 +33,24 @@ public:
 
 
     virtual void event(GEvent&) override;
     virtual void event(GEvent&) override;
 
 
-    bool is_being_dragged() const { return m_is_being_dragged; }
-    void set_is_being_dragged(bool b) { m_is_being_dragged = b; }
-
     bool is_visible() const;
     bool is_visible() const;
 
 
     void close();
     void close();
 
 
+    void set_main_widget(GWidget*);
+
     GraphicsBitmap* backing() { return m_backing.ptr(); }
     GraphicsBitmap* backing() { return m_backing.ptr(); }
 
 
+    void show();
+
+    void update();
+
 private:
 private:
     String m_title;
     String m_title;
     Rect m_rect;
     Rect m_rect;
-    bool m_is_being_dragged { false };
 
 
     RetainPtr<GraphicsBitmap> m_backing;
     RetainPtr<GraphicsBitmap> m_backing;
     int m_window_id { -1 };
     int m_window_id { -1 };
+    GWidget* m_main_widget { nullptr };
 };
 };
 
 

+ 1 - 0
Userland/.gitignore

@@ -22,4 +22,5 @@ touch
 sync
 sync
 more
 more
 guitest
 guitest
+guitest2
 sysctl
 sysctl

+ 5 - 0
Userland/Makefile

@@ -20,6 +20,7 @@ OBJS = \
        touch.o \
        touch.o \
        more.o \
        more.o \
        guitest.o \
        guitest.o \
+       guitest2.o \
        sysctl.o
        sysctl.o
 
 
 APPS = \
 APPS = \
@@ -45,6 +46,7 @@ APPS = \
        sync \
        sync \
        more \
        more \
        guitest \
        guitest \
+       guitest2 \
        sysctl
        sysctl
 
 
 ARCH_FLAGS =
 ARCH_FLAGS =
@@ -131,6 +133,9 @@ more: more.o
 guitest: guitest.o
 guitest: guitest.o
 	$(LD) -o $@ $(LDFLAGS) $< ../LibC/LibC.a
 	$(LD) -o $@ $(LDFLAGS) $< ../LibC/LibC.a
 
 
+guitest2: guitest2.o
+	$(LD) -o $@ $(LDFLAGS) $< ../LibGUI/LibGUI.a ../LibC/LibC.a
+
 sysctl: sysctl.o
 sysctl: sysctl.o
 	$(LD) -o $@ $(LDFLAGS) $< ../LibC/LibC.a
 	$(LD) -o $@ $(LDFLAGS) $< ../LibC/LibC.a
 
 

+ 54 - 0
Userland/guitest2.cpp

@@ -0,0 +1,54 @@
+#include <stdio.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <assert.h>
+#include <Kernel/Syscall.h>
+#include <SharedGraphics/GraphicsBitmap.h>
+#include <SharedGraphics/Painter.h>
+#include <LibGUI/GWindow.h>
+#include <LibGUI/GWidget.h>
+#include <LibGUI/GLabel.h>
+#include <LibGUI/GEventLoop.h>
+
+static GWindow* make_font_test_window();
+
+int main(int argc, char** argv)
+{
+    auto* window = make_font_test_window();
+    window->show();
+
+    GEventLoop loop;
+    return loop.exec();
+}
+
+GWindow* make_font_test_window()
+{
+    auto* window = new GWindow;
+    window->set_title("Font test");
+    window->set_rect({ 140, 100, 300, 80 });
+
+    auto* widget = new GWidget;
+    window->set_main_widget(widget);
+    widget->setWindowRelativeRect({ 0, 0, 300, 80 });
+
+    auto* l1 = new GLabel(widget);
+    l1->setWindowRelativeRect({ 0, 0, 300, 20 });
+    l1->setText("0123456789");
+
+    auto* l2 = new GLabel(widget);
+    l2->setWindowRelativeRect({ 0, 20, 300, 20 });
+    l2->setText("ABCDEFGHIJKLMNOPQRSTUVWXYZ");
+
+    auto* l3 = new GLabel(widget);
+    l3->setWindowRelativeRect({ 0, 40, 300, 20 });
+    l3->setText("abcdefghijklmnopqrstuvwxyz");
+
+    auto* l4 = new GLabel(widget);
+    l4->setWindowRelativeRect({ 0, 60, 300, 20 });
+    l4->setText("!\"#$%&'()*+,-./:;<=>?@[\\]^_{|}~");
+
+    return window;
+}

+ 8 - 5
WindowServer/WSEvent.h

@@ -80,9 +80,9 @@ private:
 
 
 enum class MouseButton : byte {
 enum class MouseButton : byte {
     None = 0,
     None = 0,
-    Left,
-    Middle,
-    Right,
+    Left = 1,
+    Right = 2,
+    Middle = 4,
 };
 };
 
 
 enum KeyboardKey {
 enum KeyboardKey {
@@ -121,9 +121,10 @@ private:
 
 
 class MouseEvent final : public WSEvent {
 class MouseEvent final : public WSEvent {
 public:
 public:
-    MouseEvent(Type type, int x, int y, MouseButton button = MouseButton::None)
+    MouseEvent(Type type, const Point& position, unsigned buttons, MouseButton button = MouseButton::None)
         : WSEvent(type)
         : WSEvent(type)
-        , m_position(x, y)
+        , m_position(position)
+        , m_buttons(buttons)
         , m_button(button)
         , m_button(button)
     {
     {
     }
     }
@@ -132,8 +133,10 @@ public:
     int x() const { return m_position.x(); }
     int x() const { return m_position.x(); }
     int y() const { return m_position.y(); }
     int y() const { return m_position.y(); }
     MouseButton button() const { return m_button; }
     MouseButton button() const { return m_button; }
+    unsigned buttons() const { return m_buttons; }
 
 
 private:
 private:
     Point m_position;
     Point m_position;
+    unsigned m_buttons { 0 };
     MouseButton m_button { MouseButton::None };
     MouseButton m_button { MouseButton::None };
 };
 };

+ 8 - 3
WindowServer/WSScreen.cpp

@@ -41,8 +41,13 @@ void WSScreen::on_receive_mouse_data(int dx, int dy, bool left_button, bool righ
         m_cursor_location.set_x(width() - 1);
         m_cursor_location.set_x(width() - 1);
     if (m_cursor_location.y() >= height())
     if (m_cursor_location.y() >= height())
         m_cursor_location.set_y(height() - 1);
         m_cursor_location.set_y(height() - 1);
+    unsigned buttons = 0;
+    if (left_button)
+        buttons |= (unsigned)MouseButton::Left;
+    if (right_button)
+        buttons |= (unsigned)MouseButton::Right;
     if (m_cursor_location != prev_location) {
     if (m_cursor_location != prev_location) {
-        auto event = make<MouseEvent>(WSEvent::MouseMove, m_cursor_location.x(), m_cursor_location.y());
+        auto event = make<MouseEvent>(WSEvent::MouseMove, m_cursor_location, buttons);
         WSEventLoop::the().post_event(&WSWindowManager::the(), move(event));
         WSEventLoop::the().post_event(&WSWindowManager::the(), move(event));
     }
     }
     bool prev_left_button = m_left_mouse_button_pressed;
     bool prev_left_button = m_left_mouse_button_pressed;
@@ -50,11 +55,11 @@ void WSScreen::on_receive_mouse_data(int dx, int dy, bool left_button, bool righ
     m_left_mouse_button_pressed = left_button;
     m_left_mouse_button_pressed = left_button;
     m_right_mouse_button_pressed = right_button;
     m_right_mouse_button_pressed = right_button;
     if (prev_left_button != left_button) {
     if (prev_left_button != left_button) {
-        auto event = make<MouseEvent>(left_button ? WSEvent::MouseDown : WSEvent::MouseUp, m_cursor_location.x(), m_cursor_location.y(), MouseButton::Left);
+        auto event = make<MouseEvent>(left_button ? WSEvent::MouseDown : WSEvent::MouseUp, m_cursor_location, buttons, MouseButton::Left);
         WSEventLoop::the().post_event(&WSWindowManager::the(), move(event));
         WSEventLoop::the().post_event(&WSWindowManager::the(), move(event));
     }
     }
     if (prev_right_button != right_button) {
     if (prev_right_button != right_button) {
-        auto event = make<MouseEvent>(right_button ? WSEvent::MouseDown : WSEvent::MouseUp, m_cursor_location.x(), m_cursor_location.y(), MouseButton::Right);
+        auto event = make<MouseEvent>(right_button ? WSEvent::MouseDown : WSEvent::MouseUp, m_cursor_location, buttons, MouseButton::Right);
         WSEventLoop::the().post_event(&WSWindowManager::the(), move(event));
         WSEventLoop::the().post_event(&WSWindowManager::the(), move(event));
     }
     }
     if (m_cursor_location != prev_location || prev_left_button != left_button)
     if (m_cursor_location != prev_location || prev_left_button != left_button)

+ 1 - 0
WindowServer/WSWindow.cpp

@@ -59,6 +59,7 @@ void WSWindow::event(WSEvent& event)
     case WSEvent::MouseMove:
     case WSEvent::MouseMove:
         gui_event.type = GUI_Event::Type::MouseMove;
         gui_event.type = GUI_Event::Type::MouseMove;
         gui_event.mouse.position = static_cast<MouseEvent&>(event).position();
         gui_event.mouse.position = static_cast<MouseEvent&>(event).position();
+        gui_event.mouse.button = GUI_MouseButton::NoButton;
         break;
         break;
     case WSEvent::MouseDown:
     case WSEvent::MouseDown:
         gui_event.type = GUI_Event::Type::MouseDown;
         gui_event.type = GUI_Event::Type::MouseDown;

+ 4 - 3
WindowServer/WSWindowManager.cpp

@@ -285,9 +285,10 @@ void WSWindowManager::process_mouse_event(MouseEvent& event)
                 move_to_front(*window);
                 move_to_front(*window);
                 set_active_window(window);
                 set_active_window(window);
             }
             }
-            // FIXME: Re-use the existing event instead of crafting a new one?
-            auto localEvent = make<MouseEvent>(event.type(), event.x() - window->rect().x(), event.y() - window->rect().y(), event.button());
-            window->event(*localEvent);
+            // FIXME: Should we just alter the coordinates of the existing MouseEvent and pass it through?
+            Point position { event.x() - window->rect().x(), event.y() - window->rect().y() };
+            auto local_event = make<MouseEvent>(event.type(), position, event.buttons(), event.button());
+            window->event(*local_event);
             return;
             return;
         }
         }
     }
     }