summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndreas Kling <awesomekling@gmail.com>2019-01-20 05:48:43 +0100
committerAndreas Kling <awesomekling@gmail.com>2019-01-20 05:48:43 +0100
commit8eae89a4054435dc81b534d91ec2a4f12ec7796f (patch)
tree52a2cfb7f557a4f275e787f82fb0b4ba059338df
parentb91479d9b90e1c6dd33c83d0a2cfc6ba94d1464e (diff)
downloadserenity-8eae89a4054435dc81b534d91ec2a4f12ec7796f.zip
Start bringing up LibGUI properly (formerly Widgets.)
-rw-r--r--Kernel/init.cpp1
-rwxr-xr-xKernel/makeuserland.sh4
-rwxr-xr-xKernel/sync.sh1
-rw-r--r--LibGUI/GEvent.h4
-rw-r--r--LibGUI/GEventLoop.cpp94
-rw-r--r--LibGUI/GEventLoop.h11
-rw-r--r--LibGUI/GObject.cpp2
-rw-r--r--LibGUI/GWidget.cpp4
-rw-r--r--LibGUI/GWindow.cpp61
-rw-r--r--LibGUI/GWindow.h17
-rw-r--r--Userland/.gitignore1
-rw-r--r--Userland/Makefile5
-rw-r--r--Userland/guitest2.cpp54
-rw-r--r--WindowServer/WSEvent.h13
-rw-r--r--WindowServer/WSScreen.cpp11
-rw-r--r--WindowServer/WSWindow.cpp1
-rw-r--r--WindowServer/WSWindowManager.cpp7
17 files changed, 258 insertions, 33 deletions
diff --git a/Kernel/init.cpp b/Kernel/init.cpp
index 47822bb317..24c9a7d4ed 100644
--- a/Kernel/init.cpp
+++ b/Kernel/init.cpp
@@ -104,6 +104,7 @@ static void init_stage2()
Process::create_user_process("/bin/Terminal", (uid_t)100, (gid_t)100, (pid_t)0, error, { }, move(environment), tty0);
#ifdef SPAWN_GUI_TEST_APP
Process::create_user_process("/bin/guitest", (uid_t)100, (gid_t)100, (pid_t)0, error, { }, move(environment), tty0);
+ Process::create_user_process("/bin/guitest2", (uid_t)100, (gid_t)100, (pid_t)0, error, { }, move(environment), tty0);
#endif
#ifdef SPAWN_MULTIPLE_SHELLS
Process::create_user_process("/bin/sh", (uid_t)100, (gid_t)100, (pid_t)0, error, { }, { }, tty1);
diff --git a/Kernel/makeuserland.sh b/Kernel/makeuserland.sh
index 3edcc27d81..e9f43c15a1 100755
--- a/Kernel/makeuserland.sh
+++ b/Kernel/makeuserland.sh
@@ -4,6 +4,10 @@ sudo id
make -C ../LibC clean && \
make -C ../LibC && \
+make -C ../LibGUI clean && \
+make -C ../LibGUI && \
+make -C ../Terminal clean && \
+make -C ../Terminal && \
make -C ../Userland clean && \
make -C ../Userland && \
sudo ./sync.sh
diff --git a/Kernel/sync.sh b/Kernel/sync.sh
index d69fb747b8..808f625a86 100755
--- a/Kernel/sync.sh
+++ b/Kernel/sync.sh
@@ -43,6 +43,7 @@ cp -v ../Userland/touch mnt/bin/touch
cp -v ../Userland/sync mnt/bin/sync
cp -v ../Userland/more mnt/bin/more
cp -v ../Userland/guitest mnt/bin/guitest
+cp -v ../Userland/guitest2 mnt/bin/guitest2
cp -v ../Userland/sysctl mnt/bin/sysctl
cp -v ../Terminal/Terminal mnt/bin/Terminal
sh sync-local.sh
diff --git a/LibGUI/GEvent.h b/LibGUI/GEvent.h
index 9aded85a72..0468a6c772 100644
--- a/LibGUI/GEvent.h
+++ b/LibGUI/GEvent.h
@@ -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)
{
}
diff --git a/LibGUI/GEventLoop.cpp b/LibGUI/GEventLoop.cpp
index 3a787f4f5c..84fd81ce85 100644
--- a/LibGUI/GEventLoop.cpp
+++ b/LibGUI/GEventLoop.cpp
@@ -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::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::waitForEvent()
+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;
+ }
+ }
}
diff --git a/LibGUI/GEventLoop.h b/LibGUI/GEventLoop.h
index 9d28634ecd..459b0d817f 100644
--- a/LibGUI/GEventLoop.h
+++ b/LibGUI/GEventLoop.h
@@ -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 };
};
diff --git a/LibGUI/GObject.cpp b/LibGUI/GObject.cpp
index 5b5ca3acec..13320cb265 100644
--- a/LibGUI/GObject.cpp
+++ b/LibGUI/GObject.cpp
@@ -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));
}
diff --git a/LibGUI/GWidget.cpp b/LibGUI/GWidget.cpp
index 08150f7fc0..c959dc7858 100644
--- a/LibGUI/GWidget.cpp
+++ b/LibGUI/GWidget.cpp
@@ -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)
diff --git a/LibGUI/GWindow.cpp b/LibGUI/GWindow.cpp
index fa24d66186..275d773d2a 100644
--- a/LibGUI/GWindow.cpp
+++ b/LibGUI/GWindow.cpp
@@ -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();
+}
diff --git a/LibGUI/GWindow.h b/LibGUI/GWindow.h
index 0ba848a55c..ece4b14cc3 100644
--- a/LibGUI/GWindow.h
+++ b/LibGUI/GWindow.h
@@ -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 };
};
diff --git a/Userland/.gitignore b/Userland/.gitignore
index b977ea519a..daf846e52b 100644
--- a/Userland/.gitignore
+++ b/Userland/.gitignore
@@ -22,4 +22,5 @@ touch
sync
more
guitest
+guitest2
sysctl
diff --git a/Userland/Makefile b/Userland/Makefile
index c34165565d..f0240668ed 100644
--- a/Userland/Makefile
+++ b/Userland/Makefile
@@ -20,6 +20,7 @@ OBJS = \
touch.o \
more.o \
guitest.o \
+ guitest2.o \
sysctl.o
APPS = \
@@ -45,6 +46,7 @@ APPS = \
sync \
more \
guitest \
+ guitest2 \
sysctl
ARCH_FLAGS =
@@ -131,6 +133,9 @@ more: more.o
guitest: guitest.o
$(LD) -o $@ $(LDFLAGS) $< ../LibC/LibC.a
+guitest2: guitest2.o
+ $(LD) -o $@ $(LDFLAGS) $< ../LibGUI/LibGUI.a ../LibC/LibC.a
+
sysctl: sysctl.o
$(LD) -o $@ $(LDFLAGS) $< ../LibC/LibC.a
diff --git a/Userland/guitest2.cpp b/Userland/guitest2.cpp
new file mode 100644
index 0000000000..b9f2decf3b
--- /dev/null
+++ b/Userland/guitest2.cpp
@@ -0,0 +1,54 @@
+#include <stdio.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <assert.h>
+#include <Kernel/Syscall.h>
+#include <SharedGraphics/GraphicsBitmap.h>
+#include <SharedGraphics/Painter.h>
+#include <LibGUI/GWindow.h>
+#include <LibGUI/GWidget.h>
+#include <LibGUI/GLabel.h>
+#include <LibGUI/GEventLoop.h>
+
+static GWindow* make_font_test_window();
+
+int main(int argc, char** argv)
+{
+ auto* window = make_font_test_window();
+ window->show();
+
+ GEventLoop loop;
+ return loop.exec();
+}
+
+GWindow* make_font_test_window()
+{
+ auto* window = new GWindow;
+ window->set_title("Font test");
+ window->set_rect({ 140, 100, 300, 80 });
+
+ auto* widget = new GWidget;
+ window->set_main_widget(widget);
+ widget->setWindowRelativeRect({ 0, 0, 300, 80 });
+
+ auto* l1 = new GLabel(widget);
+ l1->setWindowRelativeRect({ 0, 0, 300, 20 });
+ l1->setText("0123456789");
+
+ auto* l2 = new GLabel(widget);
+ l2->setWindowRelativeRect({ 0, 20, 300, 20 });
+ l2->setText("ABCDEFGHIJKLMNOPQRSTUVWXYZ");
+
+ auto* l3 = new GLabel(widget);
+ l3->setWindowRelativeRect({ 0, 40, 300, 20 });
+ l3->setText("abcdefghijklmnopqrstuvwxyz");
+
+ auto* l4 = new GLabel(widget);
+ l4->setWindowRelativeRect({ 0, 60, 300, 20 });
+ l4->setText("!\"#$%&'()*+,-./:;<=>?@[\\]^_{|}~");
+
+ return window;
+}
diff --git a/WindowServer/WSEvent.h b/WindowServer/WSEvent.h
index b8b817daae..dab48e2456 100644
--- a/WindowServer/WSEvent.h
+++ b/WindowServer/WSEvent.h
@@ -80,9 +80,9 @@ private:
enum class MouseButton : byte {
None = 0,
- Left,
- Middle,
- Right,
+ Left = 1,
+ Right = 2,
+ Middle = 4,
};
enum KeyboardKey {
@@ -121,9 +121,10 @@ private:
class MouseEvent final : public WSEvent {
public:
- MouseEvent(Type type, int x, int y, MouseButton button = MouseButton::None)
+ MouseEvent(Type type, const Point& position, unsigned buttons, MouseButton button = MouseButton::None)
: WSEvent(type)
- , m_position(x, y)
+ , m_position(position)
+ , m_buttons(buttons)
, m_button(button)
{
}
@@ -132,8 +133,10 @@ public:
int x() const { return m_position.x(); }
int y() const { return m_position.y(); }
MouseButton button() const { return m_button; }
+ unsigned buttons() const { return m_buttons; }
private:
Point m_position;
+ unsigned m_buttons { 0 };
MouseButton m_button { MouseButton::None };
};
diff --git a/WindowServer/WSScreen.cpp b/WindowServer/WSScreen.cpp
index 80ba9c5048..65b5c33d0b 100644
--- a/WindowServer/WSScreen.cpp
+++ b/WindowServer/WSScreen.cpp
@@ -41,8 +41,13 @@ void WSScreen::on_receive_mouse_data(int dx, int dy, bool left_button, bool righ
m_cursor_location.set_x(width() - 1);
if (m_cursor_location.y() >= height())
m_cursor_location.set_y(height() - 1);
+ unsigned buttons = 0;
+ if (left_button)
+ buttons |= (unsigned)MouseButton::Left;
+ if (right_button)
+ buttons |= (unsigned)MouseButton::Right;
if (m_cursor_location != prev_location) {
- auto event = make<MouseEvent>(WSEvent::MouseMove, m_cursor_location.x(), m_cursor_location.y());
+ auto event = make<MouseEvent>(WSEvent::MouseMove, m_cursor_location, buttons);
WSEventLoop::the().post_event(&WSWindowManager::the(), move(event));
}
bool prev_left_button = m_left_mouse_button_pressed;
@@ -50,11 +55,11 @@ void WSScreen::on_receive_mouse_data(int dx, int dy, bool left_button, bool righ
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 ? WSEvent::MouseDown : WSEvent::MouseUp, m_cursor_location.x(), m_cursor_location.y(), MouseButton::Left);
+ auto event = make<MouseEvent>(left_button ? WSEvent::MouseDown : WSEvent::MouseUp, m_cursor_location, buttons, MouseButton::Left);
WSEventLoop::the().post_event(&WSWindowManager::the(), move(event));
}
if (prev_right_button != right_button) {
- auto event = make<MouseEvent>(right_button ? WSEvent::MouseDown : WSEvent::MouseUp, m_cursor_location.x(), m_cursor_location.y(), MouseButton::Right);
+ auto event = make<MouseEvent>(right_button ? WSEvent::MouseDown : WSEvent::MouseUp, m_cursor_location, buttons, MouseButton::Right);
WSEventLoop::the().post_event(&WSWindowManager::the(), move(event));
}
if (m_cursor_location != prev_location || prev_left_button != left_button)
diff --git a/WindowServer/WSWindow.cpp b/WindowServer/WSWindow.cpp
index 005821de8f..b1d7bd8774 100644
--- a/WindowServer/WSWindow.cpp
+++ b/WindowServer/WSWindow.cpp
@@ -59,6 +59,7 @@ void WSWindow::event(WSEvent& event)
case WSEvent::MouseMove:
gui_event.type = GUI_Event::Type::MouseMove;
gui_event.mouse.position = static_cast<MouseEvent&>(event).position();
+ gui_event.mouse.button = GUI_MouseButton::NoButton;
break;
case WSEvent::MouseDown:
gui_event.type = GUI_Event::Type::MouseDown;
diff --git a/WindowServer/WSWindowManager.cpp b/WindowServer/WSWindowManager.cpp
index 6ce1c3c209..008f301069 100644
--- a/WindowServer/WSWindowManager.cpp
+++ b/WindowServer/WSWindowManager.cpp
@@ -285,9 +285,10 @@ void WSWindowManager::process_mouse_event(MouseEvent& event)
move_to_front(*window);
set_active_window(window);
}
- // FIXME: Re-use the existing event instead of crafting a new one?
- auto localEvent = make<MouseEvent>(event.type(), event.x() - window->rect().x(), event.y() - window->rect().y(), event.button());
- window->event(*localEvent);
+ // FIXME: Should we just alter the coordinates of the existing MouseEvent and pass it through?
+ Point position { event.x() - window->rect().x(), event.y() - window->rect().y() };
+ auto local_event = make<MouseEvent>(event.type(), position, event.buttons(), event.button());
+ window->event(*local_event);
return;
}
}