diff options
author | Andreas Kling <awesomekling@gmail.com> | 2019-01-20 05:48:43 +0100 |
---|---|---|
committer | Andreas Kling <awesomekling@gmail.com> | 2019-01-20 05:48:43 +0100 |
commit | 8eae89a4054435dc81b534d91ec2a4f12ec7796f (patch) | |
tree | 52a2cfb7f557a4f275e787f82fb0b4ba059338df | |
parent | b91479d9b90e1c6dd33c83d0a2cfc6ba94d1464e (diff) | |
download | serenity-8eae89a4054435dc81b534d91ec2a4f12ec7796f.zip |
Start bringing up LibGUI properly (formerly Widgets.)
-rw-r--r-- | Kernel/init.cpp | 1 | ||||
-rwxr-xr-x | Kernel/makeuserland.sh | 4 | ||||
-rwxr-xr-x | Kernel/sync.sh | 1 | ||||
-rw-r--r-- | LibGUI/GEvent.h | 4 | ||||
-rw-r--r-- | LibGUI/GEventLoop.cpp | 94 | ||||
-rw-r--r-- | LibGUI/GEventLoop.h | 11 | ||||
-rw-r--r-- | LibGUI/GObject.cpp | 2 | ||||
-rw-r--r-- | LibGUI/GWidget.cpp | 4 | ||||
-rw-r--r-- | LibGUI/GWindow.cpp | 61 | ||||
-rw-r--r-- | LibGUI/GWindow.h | 17 | ||||
-rw-r--r-- | Userland/.gitignore | 1 | ||||
-rw-r--r-- | Userland/Makefile | 5 | ||||
-rw-r--r-- | Userland/guitest2.cpp | 54 | ||||
-rw-r--r-- | WindowServer/WSEvent.h | 13 | ||||
-rw-r--r-- | WindowServer/WSScreen.cpp | 11 | ||||
-rw-r--r-- | WindowServer/WSWindow.cpp | 1 | ||||
-rw-r--r-- | WindowServer/WSWindowManager.cpp | 7 |
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; } } |