Parcourir la source

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. :^)
Andreas Kling il y a 6 ans
Parent
commit
e5e295052f

+ 14 - 0
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()
+{
+}

+ 13 - 0
Kernel/PS2MouseDevice.h

@@ -3,11 +3,17 @@
 #include <VirtualFileSystem/CharacterDevice.h>
 #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;
+};

+ 32 - 0
Widgets/AbstractScreen.cpp

@@ -2,6 +2,7 @@
 #include "EventLoop.h"
 #include "Event.h"
 #include "Widget.h"
+#include "WindowManager.h"
 #include <AK/Assertions.h>
 
 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<MouseEvent>(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<MouseEvent>(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<MouseEvent>(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();
+}

+ 13 - 1
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 };
 };
 

+ 1 - 1
Widgets/EventLoop.cpp

@@ -53,7 +53,7 @@ int EventLoop::exec()
 
 void EventLoop::postEvent(Object* receiver, OwnPtr<Event>&& 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) });
 }
 

+ 10 - 2
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;
     }
 

+ 7 - 0
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<GraphicsBitmap> m_target;
     Window* m_window { nullptr };
+    DrawOp m_draw_op { DrawOp::Copy };
 };

+ 5 - 0
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 };

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

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