summaryrefslogtreecommitdiff
path: root/Applications/Terminal
diff options
context:
space:
mode:
authorAndreas Kling <awesomekling@gmail.com>2019-02-10 14:28:39 +0100
committerAndreas Kling <awesomekling@gmail.com>2019-02-10 14:28:39 +0100
commit53d34a0885962b49015b89b884049a47f956da90 (patch)
tree9242dcc02c1b2f1ae42ea897a15c697ac0008bf1 /Applications/Terminal
parentae4811fbae3f9c5c0ec50ff7c8a2f92f74f363f7 (diff)
downloadserenity-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/Terminal')
-rw-r--r--Applications/Terminal/Makefile2
-rw-r--r--Applications/Terminal/Terminal.cpp166
-rw-r--r--Applications/Terminal/Terminal.h28
-rw-r--r--Applications/Terminal/main.cpp55
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(&params);
- 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;
}