mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-11-25 17:10:23 +00:00
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:
parent
31667b47a5
commit
e5e295052f
Notes:
sideshowbarker
2024-07-19 16:05:02 +09:00
Author: https://github.com/awesomekling Commit: https://github.com/SerenityOS/serenity/commit/e5e295052fa
10 changed files with 117 additions and 5 deletions
|
@ -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()
|
||||
{
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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 };
|
||||
};
|
||||
|
||||
|
|
|
@ -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) });
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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 };
|
||||
};
|
||||
|
|
|
@ -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 };
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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 };
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue