diff options
author | Andreas Kling <awesomekling@gmail.com> | 2019-02-10 14:28:39 +0100 |
---|---|---|
committer | Andreas Kling <awesomekling@gmail.com> | 2019-02-10 14:28:39 +0100 |
commit | 53d34a0885962b49015b89b884049a47f956da90 (patch) | |
tree | 9242dcc02c1b2f1ae42ea897a15c697ac0008bf1 /Applications | |
parent | ae4811fbae3f9c5c0ec50ff7c8a2f92f74f363f7 (diff) | |
download | serenity-53d34a0885962b49015b89b884049a47f956da90.zip |
Port Terminal to LibGUI.
To facilitate listening for action on arbitrary file descriptors,
I've added a GNotifier class. It's quite simple but very useful:
GNotifier notifier(fd, GNotifier::Read);
notifier.on_ready_to_read = [this] (GNotifier& fd) {
// read from fd or whatever else you like :^)
};
The callback will get invoked by GEventLoop when select() says we
have something to read on the fd.
Diffstat (limited to 'Applications')
-rw-r--r-- | Applications/Terminal/Makefile | 2 | ||||
-rw-r--r-- | Applications/Terminal/Terminal.cpp | 166 | ||||
-rw-r--r-- | Applications/Terminal/Terminal.h | 28 | ||||
-rw-r--r-- | Applications/Terminal/main.cpp | 55 |
4 files changed, 126 insertions, 125 deletions
diff --git a/Applications/Terminal/Makefile b/Applications/Terminal/Makefile index 6f8dde1e3e..ac2ed4ba57 100644 --- a/Applications/Terminal/Makefile +++ b/Applications/Terminal/Makefile @@ -23,7 +23,7 @@ LDFLAGS = -static --strip-debug -melf_i386 -e _start --gc-sections all: $(APP) $(APP): $(OBJS) - $(LD) -o $(APP) $(LDFLAGS) $(OBJS) ../../LibC/LibC.a + $(LD) -o $(APP) $(LDFLAGS) $(OBJS) ../../LibGUI/LibGUI.a ../../LibC/LibC.a .cpp.o: @echo "CXX $<"; $(CXX) $(CXXFLAGS) -o $@ -c $< diff --git a/Applications/Terminal/Terminal.cpp b/Applications/Terminal/Terminal.cpp index f5d1f09ef3..68ce1d4691 100644 --- a/Applications/Terminal/Terminal.cpp +++ b/Applications/Terminal/Terminal.cpp @@ -8,40 +8,17 @@ #include <LibC/stdlib.h> #include <LibC/unistd.h> #include <LibC/stdio.h> -#include <LibC/gui.h> +#include <LibGUI/GWindow.h> +#include <Kernel/KeyCode.h> //#define TERMINAL_DEBUG -void Terminal::create_window() +Terminal::Terminal(int ptm_fd) + : m_ptm_fd(ptm_fd) + , m_font(Font::default_font()) { - m_pixel_width = m_columns * font().glyph_width() + m_inset * 2; - m_pixel_height = (m_rows * (font().glyph_height() + m_line_spacing)) + (m_inset * 2) - m_line_spacing; - - GUI_WindowParameters params; - params.rect = { { 300, 300 }, { m_pixel_width, m_pixel_height } }; - params.background_color = 0x000000; - strcpy(params.title, "Terminal"); - m_window_id = gui_create_window(¶ms); - ASSERT(m_window_id > 0); - if (m_window_id < 0) { - perror("gui_create_window"); - exit(1); - } - - // NOTE: We never release the backing store. - GUI_WindowBackingStoreInfo info; - int rc = gui_get_window_backing_store(m_window_id, &info); - if (rc < 0) { - perror("gui_get_window_backing_store"); - exit(1); - } - - m_backing = GraphicsBitmap::create_wrapper(info.size, info.pixels); -} + set_fill_with_background_color(false); -Terminal::Terminal() - : m_font(Font::default_font()) -{ m_line_height = font().glyph_height() + m_line_spacing; set_size(80, 25); @@ -54,6 +31,12 @@ Terminal::Terminal() m_lines = new Line*[rows()]; for (size_t i = 0; i < rows(); ++i) m_lines[i] = new Line(columns()); + + m_pixel_width = m_columns * font().glyph_width() + m_inset * 2; + m_pixel_height = (m_rows * (font().glyph_height() + m_line_spacing)) + (m_inset * 2) - m_line_spacing; + + set_size_policy(SizePolicy::Fixed, SizePolicy::Fixed); + set_preferred_size({ m_pixel_width, m_pixel_height }); } Terminal::Line::Line(word columns) @@ -61,7 +44,6 @@ Terminal::Line::Line(word columns) { characters = new byte[length]; attributes = new Attribute[length]; - did_paint = false; memset(characters, ' ', length); } @@ -623,13 +605,49 @@ bool Terminal::Line::has_only_one_background_color() const return true; } -void Terminal::paint() +void Terminal::event(GEvent& event) { - Rect rect { 0, 0, m_pixel_width, m_pixel_height }; - Painter painter(*m_backing); + if (event.type() == GEvent::WindowBecameActive || event.type() == GEvent::WindowBecameInactive) { + m_in_active_window = event.type() == GEvent::WindowBecameActive; + invalidate_cursor(); + update(); + } + return GWidget::event(event); +} - for (size_t i = 0; i < rows(); ++i) - line(i).did_paint = false; +void Terminal::keydown_event(GKeyEvent& event) +{ + char ch = !event.text().is_empty() ? event.text()[0] : 0; + if (event.ctrl()) { + if (ch >= 'a' && ch <= 'z') { + ch = ch - 'a' + 1; + } else if (ch == '\\') { + ch = 0x1c; + } + } + switch (event.key()) { + case KeyCode::Key_Up: + write(m_ptm_fd, "\033[A", 3); + break; + case KeyCode::Key_Down: + write(m_ptm_fd, "\033[B", 3); + break; + case KeyCode::Key_Right: + write(m_ptm_fd, "\033[C", 3); + break; + case KeyCode::Key_Left: + write(m_ptm_fd, "\033[D", 3); + break; + default: + write(m_ptm_fd, &ch, 1); + break; + } +} + +void Terminal::paint_event(GPaintEvent&) +{ + Rect rect { 0, 0, m_pixel_width, m_pixel_height }; + Painter painter(*this); if (m_rows_to_scroll_backing_store && m_rows_to_scroll_backing_store < m_rows) { int first_scanline = m_inset; @@ -637,11 +655,11 @@ void Terminal::paint() int num_rows_to_memcpy = m_rows - m_rows_to_scroll_backing_store; int scanlines_to_copy = (num_rows_to_memcpy * m_line_height) - m_line_spacing; fast_dword_copy( - m_backing->scanline(first_scanline), - m_backing->scanline(second_scanline), + painter.target()->scanline(first_scanline), + painter.target()->scanline(second_scanline), scanlines_to_copy * m_pixel_width ); - m_need_full_invalidation = true; + m_need_full_flush = true; line(max(0, m_cursor_row - m_rows_to_scroll_backing_store)).dirty = true; } m_rows_to_scroll_backing_store = 0; @@ -660,7 +678,6 @@ void Terminal::paint() for (word column = 0; column < m_columns; ++column) { bool should_reverse_fill_for_cursor = m_in_active_window && row == m_cursor_row && column == m_cursor_column; auto& attribute = line.attributes[column]; - line.did_paint = true; char ch = line.characters[column]; auto character_rect = glyph_rect(row, column); if (!has_only_one_background_color || should_reverse_fill_for_cursor) { @@ -678,71 +695,34 @@ void Terminal::paint() painter.draw_rect(cell_rect, lookup_color(line(m_cursor_row).attributes[m_cursor_column].foreground_color)); } - line(m_cursor_row).did_paint = true; - - if (m_belling) { - m_need_full_invalidation = true; + if (m_belling) painter.draw_rect(rect, Color::Red); - } +} - if (m_need_full_invalidation) { - did_paint(); - m_need_full_invalidation = false; +void Terminal::set_window_title(String&& title) +{ + auto* w = window(); + if (!w) return; - } - - Rect painted_rect; - for (int i = 0; i < m_rows; ++i) { - if (line(i).did_paint) - painted_rect = painted_rect.united(row_rect(i)); - } - did_paint(painted_rect); + w->set_title(move(title)); } -void Terminal::did_paint(const Rect& a_rect) +void Terminal::invalidate_cursor() { - GUI_Rect rect = a_rect; - int rc = gui_notify_paint_finished(m_window_id, a_rect.is_null() ? nullptr : &rect); - if (rc < 0) { - perror("gui_notify_paint_finished"); - exit(1); - } + line(m_cursor_row).dirty = true; } -void Terminal::update() +void Terminal::flush_dirty_lines() { + if (m_need_full_flush) { + update(); + m_need_full_flush = false; + return; + } Rect rect; for (int i = 0; i < m_rows; ++i) { - if (line(i).did_paint) + if (line(i).dirty) rect = rect.united(row_rect(i)); } - GUI_Rect gui_rect = rect; - int rc = gui_invalidate_window(m_window_id, rect.is_null() ? nullptr : &gui_rect); - if (rc < 0) { - perror("gui_invalidate_window"); - exit(1); - } -} - -void Terminal::set_window_title(const String& title) -{ - int rc = gui_set_window_title(m_window_id, title.characters(), title.length()); - if (rc < 0) { - perror("gui_set_window_title"); - exit(1); - } -} - -void Terminal::set_in_active_window(bool b) -{ - if (m_in_active_window == b) - return; - m_in_active_window = b; - invalidate_cursor(); - update(); -} - -void Terminal::invalidate_cursor() -{ - line(m_cursor_row).dirty = true; + update(rect); } diff --git a/Applications/Terminal/Terminal.h b/Applications/Terminal/Terminal.h index e5e7d81f34..64642104a4 100644 --- a/Applications/Terminal/Terminal.h +++ b/Applications/Terminal/Terminal.h @@ -5,31 +5,33 @@ #include <AK/Vector.h> #include <SharedGraphics/GraphicsBitmap.h> #include <SharedGraphics/Rect.h> +#include <LibGUI/GWidget.h> class Font; -class Terminal { +class Terminal final : public GWidget { public: - Terminal(); - ~Terminal(); + explicit Terminal(int ptm_fd); + virtual ~Terminal() override; void create_window(); - void paint(); void on_char(byte); - void set_in_active_window(bool); - void update(); + void flush_dirty_lines(); private: + virtual void event(GEvent&) override; + virtual void paint_event(GPaintEvent&) override; + virtual void keydown_event(GKeyEvent&) override; + virtual const char* class_name() const override { return "Terminal"; } + Font& font() { return *m_font; } void scroll_up(); void newline(); void set_cursor(unsigned row, unsigned column); void put_character_at(unsigned row, unsigned column, byte ch); void invalidate_cursor(); - void did_paint(const Rect& = Rect()); - void invalidate_window(const Rect& = Rect()); - void set_window_title(const String&); + void set_window_title(String&&); void inject_string(const String&); void unimplemented_escape(); @@ -83,7 +85,6 @@ private: bool has_only_one_background_color() const; byte* characters { nullptr }; Attribute* attributes { nullptr }; - bool did_paint { false }; bool dirty { false }; word length { 0 }; }; @@ -125,9 +126,6 @@ private: byte* m_horizontal_tabs { nullptr }; bool m_belling { false }; - int m_window_id { 0 }; - RetainPtr<GraphicsBitmap> m_backing; - int m_pixel_width { 0 }; int m_pixel_height { 0 }; int m_rows_to_scroll_backing_store { 0 }; @@ -136,8 +134,10 @@ private: int m_line_spacing { 4 }; int m_line_height { 0 }; + int m_ptm_fd { -1 }; + bool m_in_active_window { false }; - bool m_need_full_invalidation { false }; + bool m_need_full_flush { false }; RetainPtr<Font> m_font; }; diff --git a/Applications/Terminal/main.cpp b/Applications/Terminal/main.cpp index 36cea4a693..c7ad546c8e 100644 --- a/Applications/Terminal/main.cpp +++ b/Applications/Terminal/main.cpp @@ -5,14 +5,15 @@ #include <stdlib.h> #include <fcntl.h> #include <assert.h> -#include <SharedGraphics/Font.h> -#include <SharedGraphics/GraphicsBitmap.h> -#include <SharedGraphics/Painter.h> #include <sys/ioctl.h> #include <sys/select.h> #include <LibC/gui.h> #include "Terminal.h" #include <Kernel/KeyCode.h> +#include <LibGUI/GEventLoop.h> +#include <LibGUI/GNotifier.h> +#include <LibGUI/GWidget.h> +#include <LibGUI/GWindow.h> static void make_shell(int ptm_fd) { @@ -52,11 +53,6 @@ static void make_shell(int ptm_fd) } } -static int max(int a, int b) -{ - return a > b ? a : b; -} - int main(int, char**) { int ptm_fd = open("/dev/ptmx", O_RDWR); @@ -67,16 +63,39 @@ int main(int, char**) make_shell(ptm_fd); - int event_fd = open("/dev/gui_events", O_RDONLY); - if (event_fd < 0) { - perror("open"); - return 1; - } + GEventLoop loop; + + auto* window = new GWindow; + window->set_should_exit_app_on_close(true); - Terminal terminal; - terminal.create_window(); - terminal.update(); + Terminal terminal(ptm_fd); + window->set_main_widget(&terminal); + GNotifier ptm_notifier(ptm_fd, GNotifier::Read); + ptm_notifier.on_ready_to_read = [&terminal] (GNotifier& notifier) { + byte buffer[BUFSIZ]; + ssize_t nread = read(notifier.fd(), buffer, sizeof(buffer)); + if (nread < 0) { + dbgprintf("Terminal read error: %s\n", strerror(errno)); + perror("read(ptm)"); + GEventLoop::main().exit(1); + return; + } + if (nread == 0) { + dbgprintf("Terminal: EOF on master pty, closing.\n"); + GEventLoop::main().exit(0); + return; + } + for (ssize_t i = 0; i < nread; ++i) + terminal.on_char(buffer[i]); + terminal.flush_dirty_lines(); + }; + + window->show(); + + return loop.exec(); + +#if 0 for (;;) { fd_set rfds; FD_ZERO(&rfds); @@ -112,11 +131,12 @@ int main(int, char**) perror("read(event)"); return 1; } + assert(nread != 0); assert(nread == sizeof(event)); if (event.type == GUI_Event::Type::Paint) { - terminal.paint(); + terminal.update(); } else if (event.type == GUI_Event::Type::KeyDown) { char ch = event.key.character; if (event.key.ctrl) { @@ -151,5 +171,6 @@ int main(int, char**) } } } +#endif return 0; } |