1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-25 06:47:35 +00:00

Start bringing up LibGUI properly (formerly Widgets.)

This commit is contained in:
Andreas Kling 2019-01-20 05:48:43 +01:00
parent b91479d9b9
commit 8eae89a405
17 changed files with 258 additions and 33 deletions

View file

@ -134,9 +134,9 @@ private:
class GMouseEvent final : public GEvent {
public:
GMouseEvent(Type type, int x, int y, GMouseButton button = GMouseButton::None)
GMouseEvent(Type type, const Point& position, GMouseButton button = GMouseButton::None)
: GEvent(type)
, m_position(x, y)
, m_position(position)
, m_button(button)
{
}

View file

@ -1,6 +1,13 @@
#include "GEventLoop.h"
#include "GEvent.h"
#include "GObject.h"
#include "GWindow.h"
#include <LibC/unistd.h>
#include <LibC/stdio.h>
#include <LibC/fcntl.h>
#include <LibC/string.h>
#include <LibC/sys/select.h>
#include <LibC/gui.h>
static GEventLoop* s_mainGEventLoop;
@ -27,13 +34,19 @@ GEventLoop& GEventLoop::main()
int GEventLoop::exec()
{
m_event_fd = open("/dev/gui_events", O_RDONLY);
if (m_event_fd < 0) {
perror("GEventLoop::exec(): open");
exit(1);
}
m_running = true;
for (;;) {
if (m_queuedEvents.is_empty())
waitForEvent();
if (m_queued_events.is_empty())
wait_for_event();
Vector<QueuedEvent> events;
{
events = move(m_queuedEvents);
events = move(m_queued_events);
}
for (auto& queuedEvent : events) {
auto* receiver = queuedEvent.receiver;
@ -56,12 +69,81 @@ int GEventLoop::exec()
}
}
void GEventLoop::postEvent(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());
m_queuedEvents.append({ receiver, move(event) });
m_queued_events.append({ receiver, move(event) });
}
void GEventLoop::waitForEvent()
void GEventLoop::handle_paint_event(const GUI_Event& event, GWindow& window)
{
post_event(&window, make<GPaintEvent>(event.paint.rect));
}
void GEventLoop::handle_mouse_event(const GUI_Event& event, GWindow& window)
{
GMouseEvent::Type type;
switch (event.type) {
case GUI_Event::Type::MouseMove: type = GEvent::MouseMove; break;
case GUI_Event::Type::MouseUp: type = GEvent::MouseUp; break;
case GUI_Event::Type::MouseDown: type = GEvent::MouseDown; break;
default: ASSERT_NOT_REACHED(); break;
}
GMouseButton button { GMouseButton::None };
switch (event.mouse.button) {
case GUI_MouseButton::NoButton: button = GMouseButton::None; break;
case GUI_MouseButton::Left: button = GMouseButton::Left; break;
case GUI_MouseButton::Right: button = GMouseButton::Right; break;
case GUI_MouseButton::Middle: button = GMouseButton::Middle; break;
default: ASSERT_NOT_REACHED(); break;
}
auto mouse_event = make<GMouseEvent>(type, event.mouse.position, button);
}
void GEventLoop::wait_for_event()
{
fd_set rfds;
FD_ZERO(&rfds);
FD_SET(m_event_fd, &rfds);
int rc = select(m_event_fd + 1, &rfds, nullptr, nullptr, nullptr);
if (rc < 0) {
ASSERT_NOT_REACHED();
}
if (!FD_ISSET(m_event_fd, &rfds))
return;
for (;;) {
GUI_Event event;
ssize_t nread = read(m_event_fd, &event, sizeof(GUI_Event));
if (nread < 0) {
perror("read");
exit(1); // FIXME: This should cause EventLoop::exec() to return 1.
}
if (nread == 0)
break;
assert(nread == sizeof(event));
auto* window = GWindow::from_window_id(event.window_id);
if (!window) {
dbgprintf("GEventLoop received event for invalid window ID %d\n", event.window_id);
}
switch (event.type) {
case GUI_Event::Type::Paint:
dbgprintf("WID=%x Paint [%d,%d %dx%d]\n", event.window_id, event.paint.rect.location.x, event.paint.rect.location.y, event.paint.rect.size.width, event.paint.rect.size.height); break;
handle_paint_event(event, *window);
break;
case GUI_Event::Type::MouseDown:
case GUI_Event::Type::MouseUp:
case GUI_Event::Type::MouseMove:
dbgprintf("WID=%x MouseEvent %d,%d\n", event.window_id, event.mouse.position.x, event.mouse.position.y);
handle_mouse_event(event, *window);
break;
case GUI_Event::Type::WindowActivated:
dbgprintf("WID=%x WindowActivated\n", event.window_id);
break;
case GUI_Event::Type::WindowDeactivated:
dbgprintf("WID=%x WindowDeactivated\n", event.window_id);
break;
}
}
}

View file

@ -5,6 +5,8 @@
#include <AK/Vector.h>
class GObject;
class GWindow;
struct GUI_Event;
class GEventLoop {
public:
@ -13,7 +15,7 @@ public:
int exec();
void postEvent(GObject* receiver, OwnPtr<GEvent>&&);
void post_event(GObject* receiver, OwnPtr<GEvent>&&);
static GEventLoop& main();
@ -22,13 +24,16 @@ public:
bool running() const { return m_running; }
private:
void waitForEvent();
void wait_for_event();
void handle_paint_event(const GUI_Event&, GWindow&);
void handle_mouse_event(const GUI_Event&, GWindow&);
struct QueuedEvent {
GObject* receiver { nullptr };
OwnPtr<GEvent> event;
};
Vector<QueuedEvent> m_queuedEvents;
Vector<QueuedEvent> m_queued_events;
int m_event_fd { -1 };
bool m_running { false };
};

View file

@ -71,6 +71,6 @@ void GObject::stopTimer()
void GObject::deleteLater()
{
GEventLoop::main().postEvent(this, make<GEvent>(GEvent::DeferredDestroy));
GEventLoop::main().post_event(this, make<GEvent>(GEvent::DeferredDestroy));
}

View file

@ -37,8 +37,6 @@ void GWidget::event(GEvent& event)
case GEvent::Paint:
m_hasPendingPaintEvent = false;
if (auto* win = window()) {
if (win->is_being_dragged())
return;
if (!win->is_visible())
return;
}
@ -112,7 +110,7 @@ void GWidget::update()
if (m_hasPendingPaintEvent)
return;
m_hasPendingPaintEvent = true;
GEventLoop::main().postEvent(w, make<GPaintEvent>(relativeRect()));
GEventLoop::main().post_event(w, make<GPaintEvent>(relativeRect()));
}
GWidget::HitTestResult GWidget::hitTest(int x, int y)

View file

@ -2,10 +2,51 @@
#include "GEvent.h"
#include "GEventLoop.h"
#include <SharedGraphics/GraphicsBitmap.h>
#include <LibC/gui.h>
#include <LibC/stdio.h>
#include <LibC/stdlib.h>
#include <AK/HashMap.h>
GWindow::GWindow(int window_id)
: m_window_id(window_id)
static HashMap<int, GWindow*>* s_windows;
static HashMap<int, GWindow*>& windows()
{
if (!s_windows)
s_windows = new HashMap<int, GWindow*>;
return *s_windows;
}
GWindow* GWindow::from_window_id(int window_id)
{
auto it = windows().find(window_id);
if (it != windows().end())
return (*it).value;
return nullptr;
}
GWindow::GWindow(GObject* parent)
: GObject(parent)
{
GUI_CreateWindowParameters wparams;
wparams.rect = { { 100, 400 }, { 140, 140 } };
wparams.background_color = 0xffc0c0;
strcpy(wparams.title, "GWindow");
m_window_id = gui_create_window(&wparams);
if (m_window_id < 0) {
perror("gui_create_window");
exit(1);
}
GUI_WindowBackingStoreInfo backing;
int 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);
windows().set(m_window_id, this);
}
GWindow::~GWindow()
@ -40,3 +81,19 @@ void GWindow::close()
{
}
void GWindow::show()
{
}
void GWindow::update()
{
gui_invalidate_window(m_window_id, nullptr);
}
void GWindow::set_main_widget(GWidget* widget)
{
if (m_main_widget == widget)
return;
m_main_widget = widget;
update();
}

View file

@ -5,11 +5,15 @@
#include <SharedGraphics/GraphicsBitmap.h>
#include <AK/AKString.h>
class GWidget;
class GWindow final : public GObject {
public:
explicit GWindow(int window_id);
GWindow(GObject* parent = nullptr);
virtual ~GWindow() override;
static GWindow* from_window_id(int);
int window_id() const { return m_window_id; }
String title() const { return m_title; }
@ -29,21 +33,24 @@ public:
virtual void event(GEvent&) override;
bool is_being_dragged() const { return m_is_being_dragged; }
void set_is_being_dragged(bool b) { m_is_being_dragged = b; }
bool is_visible() const;
void close();
void set_main_widget(GWidget*);
GraphicsBitmap* backing() { return m_backing.ptr(); }
void show();
void update();
private:
String m_title;
Rect m_rect;
bool m_is_being_dragged { false };
RetainPtr<GraphicsBitmap> m_backing;
int m_window_id { -1 };
GWidget* m_main_widget { nullptr };
};