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. :^)
This commit is contained in:
Andreas Kling 2019-01-11 03:52:09 +01:00
parent 31667b47a5
commit e5e295052f
Notes: sideshowbarker 2024-07-19 16:05:02 +09:00
10 changed files with 117 additions and 5 deletions

View file

@ -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()
{
}

View file

@ -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;
};

View file

@ -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();
}

View file

@ -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 };
};

View file

@ -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) });
}

View file

@ -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;
}

View file

@ -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 };
};

View file

@ -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 };

View file

@ -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);
}

View file

@ -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 };
};