From e5e295052faf8ea1e622c8d67c766f8213c71b81 Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Fri, 11 Jan 2019 03:52:09 +0100 Subject: [PATCH] Hook up the PS2MouseDevice to the AbstractScreen+WindowManager. Render the mouse cursor by xor'ing the pixels. I don't know anything about hardware cursors yet and this way we don't need to recompose the window hierarchy every time you move the mouse. :^) --- Kernel/PS2MouseDevice.cpp | 14 ++++++++++++++ Kernel/PS2MouseDevice.h | 13 +++++++++++++ Widgets/AbstractScreen.cpp | 32 ++++++++++++++++++++++++++++++++ Widgets/AbstractScreen.h | 14 +++++++++++++- Widgets/EventLoop.cpp | 2 +- Widgets/Painter.cpp | 12 ++++++++++-- Widgets/Painter.h | 7 +++++++ Widgets/Point.h | 5 +++++ Widgets/WindowManager.cpp | 19 ++++++++++++++++++- Widgets/WindowManager.h | 4 ++++ 10 files changed, 117 insertions(+), 5 deletions(-) diff --git a/Kernel/PS2MouseDevice.cpp b/Kernel/PS2MouseDevice.cpp index 497c655d046..6ae04de6bc3 100644 --- a/Kernel/PS2MouseDevice.cpp +++ b/Kernel/PS2MouseDevice.cpp @@ -1,10 +1,13 @@ #include "PS2MouseDevice.h" #include "IO.h" +static PS2MouseDevice* s_the; + PS2MouseDevice::PS2MouseDevice() : IRQHandler(12) , CharacterDevice(10, 1) { + s_the = this; initialize(); } @@ -12,6 +15,11 @@ PS2MouseDevice::~PS2MouseDevice() { } +PS2MouseDevice& PS2MouseDevice::the() +{ + return *s_the; +} + void PS2MouseDevice::handle_irq() { byte data = IO::in8(0x60); @@ -32,6 +40,8 @@ void PS2MouseDevice::handle_irq() (m_data[0] & 1) ? "Left" : "", (m_data[0] & 2) ? "Right" : "" ); + if (m_client) + m_client->did_receive_mouse_data(m_data[1], -m_data[2], m_data[0] & 1, m_data[0] & 2); break; } } @@ -120,3 +130,7 @@ ssize_t PS2MouseDevice::write(const byte *buffer, size_t buffer_size) ASSERT_NOT_REACHED(); return 0; } + +MouseClient::~MouseClient() +{ +} diff --git a/Kernel/PS2MouseDevice.h b/Kernel/PS2MouseDevice.h index d7587949d40..9ed77704993 100644 --- a/Kernel/PS2MouseDevice.h +++ b/Kernel/PS2MouseDevice.h @@ -3,11 +3,17 @@ #include #include "IRQHandler.h" +class MouseClient; + class PS2MouseDevice final : public IRQHandler, public CharacterDevice { public: PS2MouseDevice(); virtual ~PS2MouseDevice() override; + static PS2MouseDevice& the(); + + void set_client(MouseClient* client) { m_client = client; } + private: virtual bool has_data_available_for_reading() const override; virtual ssize_t read(byte* buffer, size_t buffer_size) override; @@ -23,6 +29,13 @@ private: void wait_then_write(byte port, byte data); byte wait_then_read(byte port); + MouseClient* m_client { nullptr }; byte m_data_state { 0 }; signed_byte m_data[3]; }; + +class MouseClient { +public: + virtual ~MouseClient(); + virtual void did_receive_mouse_data(int dx, int dy, bool left_button, bool right_button) = 0; +}; diff --git a/Widgets/AbstractScreen.cpp b/Widgets/AbstractScreen.cpp index 948be12137e..d77318ef144 100644 --- a/Widgets/AbstractScreen.cpp +++ b/Widgets/AbstractScreen.cpp @@ -2,6 +2,7 @@ #include "EventLoop.h" #include "Event.h" #include "Widget.h" +#include "WindowManager.h" #include static AbstractScreen* s_the; @@ -24,9 +25,40 @@ AbstractScreen::AbstractScreen(unsigned width, unsigned height) { ASSERT(!s_the); s_the = this; + + m_cursor_location = rect().center(); + + PS2MouseDevice::the().set_client(this); } AbstractScreen::~AbstractScreen() { } +void AbstractScreen::did_receive_mouse_data(int dx, int dy, bool left_button, bool right_button) +{ + auto prev_location = m_cursor_location; + m_cursor_location.moveBy(dx, dy); + if (m_cursor_location.x() >= width()) + m_cursor_location.setX(width() - 1); + if (m_cursor_location.y() >= height()) + m_cursor_location.setY(height() - 1); + if (m_cursor_location != prev_location) { + auto event = make(Event::MouseMove, m_cursor_location.x(), m_cursor_location.y()); + EventLoop::main().postEvent(&WindowManager::the(), move(event)); + } + bool prev_left_button = m_left_mouse_button_pressed; + bool prev_right_button = m_right_mouse_button_pressed; + m_left_mouse_button_pressed = left_button; + m_right_mouse_button_pressed = right_button; + if (prev_left_button != left_button) { + auto event = make(left_button ? Event::MouseDown : Event::MouseUp, m_cursor_location.x(), m_cursor_location.y(), MouseButton::Left); + EventLoop::main().postEvent(&WindowManager::the(), move(event)); + } + if (prev_right_button != right_button) { + auto event = make(right_button ? Event::MouseDown : Event::MouseUp, m_cursor_location.x(), m_cursor_location.y(), MouseButton::Right); + EventLoop::main().postEvent(&WindowManager::the(), move(event)); + } + if (m_cursor_location != prev_location) + WindowManager::the().redraw_cursor(); +} diff --git a/Widgets/AbstractScreen.h b/Widgets/AbstractScreen.h index 0018a073193..752a5d34aef 100644 --- a/Widgets/AbstractScreen.h +++ b/Widgets/AbstractScreen.h @@ -3,8 +3,9 @@ #include "Object.h" #include "Rect.h" #include "Size.h" +#include "PS2MouseDevice.h" -class AbstractScreen : public Object { +class AbstractScreen : public Object, public MouseClient { public: virtual ~AbstractScreen(); @@ -18,11 +19,22 @@ public: static void initialize(); + Point cursor_location() const { return m_cursor_location; } + bool left_mouse_button_pressed() const { return m_left_mouse_button_pressed; } + bool right_mouse_button_pressed() const { return m_right_mouse_button_pressed; } + protected: AbstractScreen(unsigned width, unsigned height); private: + // ^MouseClient + virtual void did_receive_mouse_data(int dx, int dy, bool left_button, bool right_button) final; + int m_width { 0 }; int m_height { 0 }; + + Point m_cursor_location; + bool m_left_mouse_button_pressed { false }; + bool m_right_mouse_button_pressed { false }; }; diff --git a/Widgets/EventLoop.cpp b/Widgets/EventLoop.cpp index 15bfb8c5a80..7238e0ee882 100644 --- a/Widgets/EventLoop.cpp +++ b/Widgets/EventLoop.cpp @@ -53,7 +53,7 @@ int EventLoop::exec() void EventLoop::postEvent(Object* receiver, OwnPtr&& event) { - printf("EventLoop::postEvent: {%u} << receiver=%p, event=%p\n", m_queuedEvents.size(), receiver, event.ptr()); + //printf("EventLoop::postEvent: {%u} << receiver=%p, event=%p\n", m_queuedEvents.size(), receiver, event.ptr()); m_queuedEvents.append({ receiver, move(event) }); } diff --git a/Widgets/Painter.cpp b/Widgets/Painter.cpp index a495dd9088a..9c07df11482 100644 --- a/Widgets/Painter.cpp +++ b/Widgets/Painter.cpp @@ -136,6 +136,14 @@ void Painter::drawPixel(const Point& p, Color color) m_target->scanline(point.y())[point.x()] = color.value(); } +void Painter::set_pixel_with_draw_op(dword& pixel, const Color& color) +{ + if (m_draw_op == DrawOp::Copy) + pixel = color.value(); + else if (m_draw_op == DrawOp::Xor) + pixel ^= color.value(); +} + void Painter::drawLine(const Point& p1, const Point& p2, Color color) { auto point1 = p1; @@ -152,7 +160,7 @@ void Painter::drawLine(const Point& p1, const Point& p2, Color color) if (point1.y() > point2.y()) swap(point1, point2); for (int y = max(point1.y(), m_clipRect.top()); y <= min(point2.y(), m_clipRect.bottom()); ++y) - m_target->scanline(y)[x] = color.value(); + set_pixel_with_draw_op(m_target->scanline(y)[x], color); return; } @@ -168,7 +176,7 @@ void Painter::drawLine(const Point& p1, const Point& p2, Color color) swap(point1, point2); auto* pixels = m_target->scanline(point1.y()); for (int x = max(point1.x(), m_clipRect.left()); x <= min(point2.x(), m_clipRect.right()); ++x) - pixels[x] = color.value(); + set_pixel_with_draw_op(pixels[x], color); return; } diff --git a/Widgets/Painter.h b/Widgets/Painter.h index b95efccab35..9a26cb0811e 100644 --- a/Widgets/Painter.h +++ b/Widgets/Painter.h @@ -30,11 +30,18 @@ public: const Font& font() const { return *m_font; } + enum class DrawOp { Copy, Xor }; + void set_draw_op(DrawOp op) { m_draw_op = op; } + DrawOp draw_op() const { return m_draw_op; } + private: + void set_pixel_with_draw_op(dword& pixel, const Color&); + Widget& m_widget; const Font* m_font; Point m_translation; Rect m_clipRect; RetainPtr m_target; Window* m_window { nullptr }; + DrawOp m_draw_op { DrawOp::Copy }; }; diff --git a/Widgets/Point.h b/Widgets/Point.h index 31a686448ee..4cb2e28057a 100644 --- a/Widgets/Point.h +++ b/Widgets/Point.h @@ -28,6 +28,11 @@ public: && m_y == other.m_y; } + bool operator!=(const Point& other) const + { + return !(*this == other); + } + private: int m_x { 0 }; int m_y { 0 }; diff --git a/Widgets/WindowManager.cpp b/Widgets/WindowManager.cpp index 8aeacaf5f0e..b1214e39ccf 100644 --- a/Widgets/WindowManager.cpp +++ b/Widgets/WindowManager.cpp @@ -281,6 +281,24 @@ void WindowManager::recompose() framebuffer.blit(window->position(), *window->backing()); } framebuffer.flush(); + m_last_drawn_cursor_location = { -1, -1 }; + redraw_cursor(); +} + +void WindowManager::redraw_cursor() +{ + auto cursor_location = AbstractScreen::the().cursor_location(); + Painter painter(*m_rootWidget); + painter.set_draw_op(Painter::DrawOp::Xor); + auto draw_cross = [&painter] (const Point& p) { + painter.drawLine({ p.x() - 10, p.y() }, { p.x() + 10, p.y() }, Color::Red); + painter.drawLine({ p.x(), p.y() - 10 }, { p.x(), p.y() + 10 }, Color::Red); + }; + if (cursor_location != m_last_drawn_cursor_location && m_last_drawn_cursor_location.x() != -1) + draw_cross(m_last_drawn_cursor_location); + draw_cross(cursor_location); + m_last_drawn_cursor_location = cursor_location; + FrameBuffer::the().flush(); } void WindowManager::event(Event& event) @@ -329,4 +347,3 @@ bool WindowManager::isVisible(Window& window) const { return m_windows.contains(&window); } - diff --git a/Widgets/WindowManager.h b/Widgets/WindowManager.h index 5d6365b75ca..f4c2335b362 100644 --- a/Widgets/WindowManager.h +++ b/Widgets/WindowManager.h @@ -36,6 +36,8 @@ public: static void initialize(); + void redraw_cursor(); + private: WindowManager(); ~WindowManager(); @@ -68,6 +70,8 @@ private: Rect m_dragStartRect; Rect m_dragEndRect; + Point m_last_drawn_cursor_location; + unsigned m_recompose_count { 0 }; unsigned m_frontmost_only_compose_count { 0 }; };