mirror of
https://github.com/RGBCube/serenity
synced 2025-05-31 07:08:10 +00:00
LibGUI: Hook up GWindow event dispatch for paint and mouse events.
This commit is contained in:
parent
dbe83f3a83
commit
ea6678b7b3
9 changed files with 72 additions and 30 deletions
|
@ -76,6 +76,7 @@ struct GUI_Event {
|
||||||
struct {
|
struct {
|
||||||
GUI_Point position;
|
GUI_Point position;
|
||||||
GUI_MouseButton button;
|
GUI_MouseButton button;
|
||||||
|
unsigned buttons;
|
||||||
} mouse;
|
} mouse;
|
||||||
struct {
|
struct {
|
||||||
char character;
|
char character;
|
||||||
|
|
|
@ -47,9 +47,9 @@ public:
|
||||||
|
|
||||||
const char* name() const { return eventNames[(unsigned)m_type]; }
|
const char* name() const { return eventNames[(unsigned)m_type]; }
|
||||||
|
|
||||||
bool isMouseEvent() const { return m_type == MouseMove || m_type == MouseDown || m_type == MouseUp; }
|
bool is_mouse_event() const { return m_type == MouseMove || m_type == MouseDown || m_type == MouseUp; }
|
||||||
bool isKeyEvent() const { return m_type == KeyUp || m_type == KeyDown; }
|
bool is_key_event() const { return m_type == KeyUp || m_type == KeyDown; }
|
||||||
bool isPaintEvent() const { return m_type == Paint; }
|
bool is_paint_event() const { return m_type == Paint; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Type m_type { Invalid };
|
Type m_type { Invalid };
|
||||||
|
@ -134,9 +134,10 @@ private:
|
||||||
|
|
||||||
class GMouseEvent final : public GEvent {
|
class GMouseEvent final : public GEvent {
|
||||||
public:
|
public:
|
||||||
GMouseEvent(Type type, const Point& position, GMouseButton button = GMouseButton::None)
|
GMouseEvent(Type type, const Point& position, unsigned buttons, GMouseButton button = GMouseButton::None)
|
||||||
: GEvent(type)
|
: GEvent(type)
|
||||||
, m_position(position)
|
, m_position(position)
|
||||||
|
, m_buttons(buttons)
|
||||||
, m_button(button)
|
, m_button(button)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -145,9 +146,11 @@ 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(); }
|
||||||
GMouseButton button() const { return m_button; }
|
GMouseButton button() const { return m_button; }
|
||||||
|
unsigned buttons() const { return m_buttons; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Point m_position;
|
Point m_position;
|
||||||
|
unsigned m_buttons { 0 };
|
||||||
GMouseButton m_button { GMouseButton::None };
|
GMouseButton m_button { GMouseButton::None };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,8 @@
|
||||||
#include <LibC/sys/select.h>
|
#include <LibC/sys/select.h>
|
||||||
#include <LibC/gui.h>
|
#include <LibC/gui.h>
|
||||||
|
|
||||||
|
//#define GEVENTLOOP_DEBUG
|
||||||
|
|
||||||
static GEventLoop* s_mainGEventLoop;
|
static GEventLoop* s_mainGEventLoop;
|
||||||
|
|
||||||
void GEventLoop::initialize()
|
void GEventLoop::initialize()
|
||||||
|
@ -34,7 +36,7 @@ GEventLoop& GEventLoop::main()
|
||||||
|
|
||||||
int GEventLoop::exec()
|
int GEventLoop::exec()
|
||||||
{
|
{
|
||||||
m_event_fd = open("/dev/gui_events", O_RDONLY);
|
m_event_fd = open("/dev/gui_events", O_RDONLY | O_NONBLOCK);
|
||||||
if (m_event_fd < 0) {
|
if (m_event_fd < 0) {
|
||||||
perror("GEventLoop::exec(): open");
|
perror("GEventLoop::exec(): open");
|
||||||
exit(1);
|
exit(1);
|
||||||
|
@ -44,14 +46,13 @@ int GEventLoop::exec()
|
||||||
for (;;) {
|
for (;;) {
|
||||||
if (m_queued_events.is_empty())
|
if (m_queued_events.is_empty())
|
||||||
wait_for_event();
|
wait_for_event();
|
||||||
Vector<QueuedEvent> events;
|
Vector<QueuedEvent> events = move(m_queued_events);
|
||||||
{
|
for (auto& queued_event : events) {
|
||||||
events = move(m_queued_events);
|
auto* receiver = queued_event.receiver;
|
||||||
}
|
auto& event = *queued_event.event;
|
||||||
for (auto& queuedEvent : events) {
|
#ifdef GEVENTLOOP_DEBUG
|
||||||
auto* receiver = queuedEvent.receiver;
|
dbgprintf("GEventLoop: GObject{%p} event %u (%s)\n", receiver, (unsigned)event.type(), event.name());
|
||||||
auto& event = *queuedEvent.event;
|
#endif
|
||||||
//printf("GEventLoop: GObject{%p} event %u (%s)\n", receiver, (unsigned)event.type(), event.name());
|
|
||||||
if (!receiver) {
|
if (!receiver) {
|
||||||
switch (event.type()) {
|
switch (event.type()) {
|
||||||
case GEvent::Quit:
|
case GEvent::Quit:
|
||||||
|
@ -71,7 +72,9 @@ int GEventLoop::exec()
|
||||||
|
|
||||||
void GEventLoop::post_event(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());
|
#ifdef GEVENTLOOP_DEBUG
|
||||||
|
dbgprintf("GEventLoop::post_event: {%u} << receiver=%p, event=%p\n", m_queued_events.size(), receiver, event.ptr());
|
||||||
|
#endif
|
||||||
m_queued_events.append({ receiver, move(event) });
|
m_queued_events.append({ receiver, move(event) });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -97,7 +100,7 @@ void GEventLoop::handle_mouse_event(const GUI_Event& event, GWindow& window)
|
||||||
case GUI_MouseButton::Middle: button = GMouseButton::Middle; break;
|
case GUI_MouseButton::Middle: button = GMouseButton::Middle; break;
|
||||||
default: ASSERT_NOT_REACHED(); break;
|
default: ASSERT_NOT_REACHED(); break;
|
||||||
}
|
}
|
||||||
auto mouse_event = make<GMouseEvent>(type, event.mouse.position, button);
|
post_event(&window, make<GMouseEvent>(type, event.mouse.position, event.mouse.buttons, button));
|
||||||
}
|
}
|
||||||
|
|
||||||
void GEventLoop::wait_for_event()
|
void GEventLoop::wait_for_event()
|
||||||
|
@ -105,7 +108,8 @@ void GEventLoop::wait_for_event()
|
||||||
fd_set rfds;
|
fd_set rfds;
|
||||||
FD_ZERO(&rfds);
|
FD_ZERO(&rfds);
|
||||||
FD_SET(m_event_fd, &rfds);
|
FD_SET(m_event_fd, &rfds);
|
||||||
int rc = select(m_event_fd + 1, &rfds, nullptr, nullptr, nullptr);
|
struct timeval timeout = { 0, 0 };
|
||||||
|
int rc = select(m_event_fd + 1, &rfds, nullptr, nullptr, m_queued_events.is_empty() ? nullptr : &timeout);
|
||||||
if (rc < 0) {
|
if (rc < 0) {
|
||||||
ASSERT_NOT_REACHED();
|
ASSERT_NOT_REACHED();
|
||||||
}
|
}
|
||||||
|
@ -126,6 +130,7 @@ void GEventLoop::wait_for_event()
|
||||||
auto* window = GWindow::from_window_id(event.window_id);
|
auto* window = GWindow::from_window_id(event.window_id);
|
||||||
if (!window) {
|
if (!window) {
|
||||||
dbgprintf("GEventLoop received event for invalid window ID %d\n", event.window_id);
|
dbgprintf("GEventLoop received event for invalid window ID %d\n", event.window_id);
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
switch (event.type) {
|
switch (event.type) {
|
||||||
case GUI_Event::Type::Paint:
|
case GUI_Event::Type::Paint:
|
||||||
|
|
|
@ -36,10 +36,6 @@ void GWidget::event(GEvent& event)
|
||||||
switch (event.type()) {
|
switch (event.type()) {
|
||||||
case GEvent::Paint:
|
case GEvent::Paint:
|
||||||
m_hasPendingPaintEvent = false;
|
m_hasPendingPaintEvent = false;
|
||||||
if (auto* win = window()) {
|
|
||||||
if (!win->is_visible())
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
return paintEvent(static_cast<GPaintEvent&>(event));
|
return paintEvent(static_cast<GPaintEvent&>(event));
|
||||||
case GEvent::Show:
|
case GEvent::Show:
|
||||||
return showEvent(static_cast<GShowEvent&>(event));
|
return showEvent(static_cast<GShowEvent&>(event));
|
||||||
|
@ -63,7 +59,6 @@ void GWidget::event(GEvent& event)
|
||||||
|
|
||||||
void GWidget::paintEvent(GPaintEvent& event)
|
void GWidget::paintEvent(GPaintEvent& event)
|
||||||
{
|
{
|
||||||
//printf("GWidget::paintEvent :)\n");
|
|
||||||
if (fillWithBackgroundColor()) {
|
if (fillWithBackgroundColor()) {
|
||||||
Painter painter(*this);
|
Painter painter(*this);
|
||||||
painter.fill_rect(rect(), backgroundColor());
|
painter.fill_rect(rect(), backgroundColor());
|
||||||
|
@ -125,7 +120,7 @@ GWidget::HitTestResult GWidget::hitTest(int x, int y)
|
||||||
return { this, x, y };
|
return { this, x, y };
|
||||||
}
|
}
|
||||||
|
|
||||||
void GWidget::setWindow(GWindow* window)
|
void GWidget::set_window(GWindow* window)
|
||||||
{
|
{
|
||||||
if (m_window == window)
|
if (m_window == window)
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -73,7 +73,7 @@ public:
|
||||||
return m_window;
|
return m_window;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setWindow(GWindow*);
|
void set_window(GWindow*);
|
||||||
|
|
||||||
GWidget* parentWidget() { return static_cast<GWidget*>(parent()); }
|
GWidget* parentWidget() { return static_cast<GWidget*>(parent()); }
|
||||||
const GWidget* parentWidget() const { return static_cast<const GWidget*>(parent()); }
|
const GWidget* parentWidget() const { return static_cast<const GWidget*>(parent()); }
|
||||||
|
@ -84,7 +84,7 @@ public:
|
||||||
const Font& font() const { return *m_font; }
|
const Font& font() const { return *m_font; }
|
||||||
void setFont(RetainPtr<Font>&&);
|
void setFont(RetainPtr<Font>&&);
|
||||||
|
|
||||||
virtual GraphicsBitmap* backing();
|
GraphicsBitmap* backing();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
GWindow* m_window { nullptr };
|
GWindow* m_window { nullptr };
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#include "GWindow.h"
|
#include "GWindow.h"
|
||||||
#include "GEvent.h"
|
#include "GEvent.h"
|
||||||
#include "GEventLoop.h"
|
#include "GEventLoop.h"
|
||||||
|
#include "GWidget.h"
|
||||||
#include <SharedGraphics/GraphicsBitmap.h>
|
#include <SharedGraphics/GraphicsBitmap.h>
|
||||||
#include <LibC/gui.h>
|
#include <LibC/gui.h>
|
||||||
#include <LibC/stdio.h>
|
#include <LibC/stdio.h>
|
||||||
|
@ -43,7 +44,6 @@ GWindow::GWindow(GObject* parent)
|
||||||
perror("gui_get_window_backing_store");
|
perror("gui_get_window_backing_store");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
m_backing = GraphicsBitmap::create_wrapper(backing.size, backing.pixels);
|
m_backing = GraphicsBitmap::create_wrapper(backing.size, backing.pixels);
|
||||||
|
|
||||||
windows().set(m_window_id, this);
|
windows().set(m_window_id, this);
|
||||||
|
@ -75,10 +75,43 @@ void GWindow::set_rect(const Rect& rect)
|
||||||
rc = gui_set_window_parameters(m_window_id, ¶ms);
|
rc = gui_set_window_parameters(m_window_id, ¶ms);
|
||||||
ASSERT(rc == 0);
|
ASSERT(rc == 0);
|
||||||
m_rect = rect;
|
m_rect = rect;
|
||||||
|
GUI_WindowBackingStoreInfo backing;
|
||||||
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GWindow::event(GEvent& event)
|
void GWindow::event(GEvent& event)
|
||||||
{
|
{
|
||||||
|
if (event.is_mouse_event()) {
|
||||||
|
if (!m_main_widget)
|
||||||
|
return;
|
||||||
|
auto& mouse_event = static_cast<GMouseEvent&>(event);
|
||||||
|
if (m_main_widget) {
|
||||||
|
auto result = m_main_widget->hitTest(mouse_event.x(), mouse_event.y());
|
||||||
|
auto local_event = make<GMouseEvent>(event.type(), Point { result.localX, result.localY }, mouse_event.buttons(), mouse_event.button());
|
||||||
|
ASSERT(result.widget);
|
||||||
|
return result.widget->event(*local_event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event.is_paint_event()) {
|
||||||
|
if (!m_main_widget)
|
||||||
|
return;
|
||||||
|
auto& paint_event = static_cast<GPaintEvent&>(event);
|
||||||
|
if (paint_event.rect().is_empty()) {
|
||||||
|
m_main_widget->paintEvent(*make<GPaintEvent>(m_main_widget->rect()));
|
||||||
|
} else {
|
||||||
|
m_main_widget->event(event);
|
||||||
|
}
|
||||||
|
int rc = gui_invalidate_window(m_window_id, nullptr);
|
||||||
|
ASSERT(rc == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return GObject::event(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GWindow::is_visible() const
|
bool GWindow::is_visible() const
|
||||||
|
@ -96,7 +129,7 @@ void GWindow::show()
|
||||||
|
|
||||||
void GWindow::update()
|
void GWindow::update()
|
||||||
{
|
{
|
||||||
gui_invalidate_window(m_window_id, nullptr);
|
GEventLoop::main().post_event(this, make<GPaintEvent>());
|
||||||
}
|
}
|
||||||
|
|
||||||
void GWindow::set_main_widget(GWidget* widget)
|
void GWindow::set_main_widget(GWidget* widget)
|
||||||
|
@ -104,5 +137,7 @@ void GWindow::set_main_widget(GWidget* widget)
|
||||||
if (m_main_widget == widget)
|
if (m_main_widget == widget)
|
||||||
return;
|
return;
|
||||||
m_main_widget = widget;
|
m_main_widget = widget;
|
||||||
|
if (widget)
|
||||||
|
widget->set_window(this);
|
||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
|
|
||||||
#ifdef LIBGUI
|
#ifdef LIBGUI
|
||||||
#include <LibGUI/GWidget.h>
|
#include <LibGUI/GWidget.h>
|
||||||
|
#include <LibGUI/GWindow.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define DEBUG_WIDGET_UNDERDRAW
|
#define DEBUG_WIDGET_UNDERDRAW
|
||||||
|
|
|
@ -17,10 +17,9 @@ static GWindow* make_font_test_window();
|
||||||
|
|
||||||
int main(int argc, char** argv)
|
int main(int argc, char** argv)
|
||||||
{
|
{
|
||||||
|
GEventLoop loop;
|
||||||
auto* window = make_font_test_window();
|
auto* window = make_font_test_window();
|
||||||
window->show();
|
window->show();
|
||||||
|
|
||||||
GEventLoop loop;
|
|
||||||
return loop.exec();
|
return loop.exec();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -29,10 +29,10 @@ void WSWindow::set_rect(const Rect& rect)
|
||||||
{
|
{
|
||||||
if (m_rect == rect)
|
if (m_rect == rect)
|
||||||
return;
|
return;
|
||||||
auto oldRect = m_rect;
|
auto old_rect = m_rect;
|
||||||
m_rect = rect;
|
m_rect = rect;
|
||||||
m_backing = GraphicsBitmap::create(m_process, m_rect.size());
|
m_backing = GraphicsBitmap::create(m_process, m_rect.size());
|
||||||
WSWindowManager::the().notify_rect_changed(*this, oldRect, m_rect);
|
WSWindowManager::the().notify_rect_changed(*this, old_rect, m_rect);
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: Just use the same types.
|
// FIXME: Just use the same types.
|
||||||
|
@ -60,16 +60,19 @@ void WSWindow::event(WSEvent& event)
|
||||||
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;
|
gui_event.mouse.button = GUI_MouseButton::NoButton;
|
||||||
|
gui_event.mouse.buttons = static_cast<MouseEvent&>(event).buttons();
|
||||||
break;
|
break;
|
||||||
case WSEvent::MouseDown:
|
case WSEvent::MouseDown:
|
||||||
gui_event.type = GUI_Event::Type::MouseDown;
|
gui_event.type = GUI_Event::Type::MouseDown;
|
||||||
gui_event.mouse.position = static_cast<MouseEvent&>(event).position();
|
gui_event.mouse.position = static_cast<MouseEvent&>(event).position();
|
||||||
gui_event.mouse.button = to_api(static_cast<MouseEvent&>(event).button());
|
gui_event.mouse.button = to_api(static_cast<MouseEvent&>(event).button());
|
||||||
|
gui_event.mouse.buttons = static_cast<MouseEvent&>(event).buttons();
|
||||||
break;
|
break;
|
||||||
case WSEvent::MouseUp:
|
case WSEvent::MouseUp:
|
||||||
gui_event.type = GUI_Event::Type::MouseUp;
|
gui_event.type = GUI_Event::Type::MouseUp;
|
||||||
gui_event.mouse.position = static_cast<MouseEvent&>(event).position();
|
gui_event.mouse.position = static_cast<MouseEvent&>(event).position();
|
||||||
gui_event.mouse.button = to_api(static_cast<MouseEvent&>(event).button());
|
gui_event.mouse.button = to_api(static_cast<MouseEvent&>(event).button());
|
||||||
|
gui_event.mouse.buttons = static_cast<MouseEvent&>(event).buttons();
|
||||||
break;
|
break;
|
||||||
case WSEvent::KeyDown:
|
case WSEvent::KeyDown:
|
||||||
gui_event.type = GUI_Event::Type::KeyDown;
|
gui_event.type = GUI_Event::Type::KeyDown;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue