diff --git a/Terminal/Terminal.cpp b/Terminal/Terminal.cpp index f432cc760d..45d434b944 100644 --- a/Terminal/Terminal.cpp +++ b/Terminal/Terminal.cpp @@ -3,12 +3,12 @@ #include #include #include -#include -#include -#include +#include +#include +#include +#include //#define TERMINAL_DEBUG -#define FAST_SCROLL void Terminal::create_window() { @@ -51,27 +51,45 @@ Terminal::Terminal() // Rightmost column is always last tab on line. m_horizontal_tabs[columns() - 1] = 1; - m_row_needs_invalidation = (bool*)(malloc(rows() * sizeof(bool))); - m_buffer = (byte*)malloc(rows() * columns()); - m_attributes = (Attribute*)malloc(rows() * columns() * sizeof(Attribute)); - memset(m_buffer, ' ', m_rows * m_columns); - for (size_t i = 0; i < rows() * columns(); ++i) - m_attributes[i].reset(); + m_lines = new Line*[rows()]; + for (size_t i = 0; i < rows(); ++i) + m_lines[i] = new Line(columns()); +} + +Terminal::Line::Line(word columns) + : length(columns) +{ + characters = new byte[length]; + attributes = new Attribute[length]; + needs_invalidation = false; + memset(characters, ' ', length); +} + +Terminal::Line::~Line() +{ + delete [] characters; + delete [] attributes; +} + +void Terminal::Line::clear() +{ + memset(characters, ' ', length); + for (word i = 0 ; i < length; ++i) + attributes[i].reset(); } Terminal::~Terminal() { - free(m_row_needs_invalidation); - free(m_buffer); - free(m_attributes); + for (size_t i = 0; i < m_rows; ++i) + delete m_lines[i]; + delete [] m_lines; free(m_horizontal_tabs); } void Terminal::clear() { - memset(m_buffer, ' ', m_rows * m_columns); - for (size_t i = 0; i < rows() * columns(); ++i) - m_attributes[i].reset(); + for (size_t i = 0; i < rows(); ++i) + line(i).clear(); set_cursor(0, 0); } @@ -348,20 +366,13 @@ void Terminal::scroll_up() { word new_row = m_cursor_row; if (m_cursor_row == (rows() - 1)) { - memcpy(m_buffer, m_buffer + m_columns, m_columns * (m_rows - 1)); -#ifdef FAST_SCROLL - ++m_rows_to_scroll_backing_store; -#else - for (size_t i = 0; i < m_rows * m_columns; ++i) { - m_attributes[i].dirty = true; - } -#endif - memset(&m_buffer[(m_rows - 1) * m_columns], ' ', m_columns); - // NOTE: We have to invalidate the cursor before memcpy()'ing the attributes. + // NOTE: We have to invalidate the cursor first. invalidate_cursor(); - memcpy(m_attributes, m_attributes + m_columns, m_columns * (m_rows - 1) * sizeof(Attribute)); - for (size_t i = 0; i < m_columns; ++i) - m_attributes[((m_rows - 1) * m_columns) + i].reset(); + delete m_lines[0]; + for (word row = 1; row < rows(); ++row) + m_lines[row - 1] = m_lines[row]; + m_lines[m_rows - 1] = new Line(m_columns); + ++m_rows_to_scroll_backing_store; } else { ++new_row; } @@ -386,9 +397,8 @@ void Terminal::put_character_at(unsigned row, unsigned column, byte ch) { ASSERT(row < rows()); ASSERT(column < columns()); - word cur = (row * m_columns) + (column); - m_buffer[cur] = ch; - m_attributes[cur] = m_current_attribute; + line(row).characters[column] = ch; + line(row).attributes[column] = m_current_attribute; } void Terminal::on_char(byte ch) @@ -503,7 +513,7 @@ inline Terminal::Attribute& Terminal::attribute_at(word row, word column) { ASSERT(row < m_rows); ASSERT(column < m_columns); - return m_attributes[(row * m_columns) + column]; + return line(row).attributes[column]; } void Terminal::paint() @@ -511,9 +521,9 @@ void Terminal::paint() Rect rect { 0, 0, m_pixel_width, m_pixel_height }; Painter painter(*m_backing); - memset(m_row_needs_invalidation, 0, rows() * sizeof(bool)); + for (size_t i = 0; i < rows(); ++i) + line(i).needs_invalidation = false; -#ifdef FAST_SCROLL if (m_rows_to_scroll_backing_store && m_rows_to_scroll_backing_store < m_rows) { int first_scanline = m_inset; int second_scanline = m_inset + (m_rows_to_scroll_backing_store * m_line_height); @@ -528,7 +538,6 @@ void Terminal::paint() attribute_at(max(0, m_cursor_row - m_rows_to_scroll_backing_store), m_cursor_column).dirty = true; } m_rows_to_scroll_backing_store = 0; -#endif for (word row = 0; row < m_rows; ++row) { for (word column = 0; column < m_columns; ++column) { @@ -536,8 +545,8 @@ void Terminal::paint() if (!attribute.dirty) continue; attribute.dirty = false; - m_row_needs_invalidation[row] = true; - char ch = m_buffer[(row * m_columns) + (column)]; + line(row).needs_invalidation = true; + char ch = line(row).characters[column]; auto character_rect = glyph_rect(row, column); auto character_background = ansi_color(attribute.background_color); painter.fill_rect(character_rect, character_background); @@ -553,7 +562,7 @@ void Terminal::paint() else painter.draw_rect(cursor_rect, Color::MidGray); - m_row_needs_invalidation[m_cursor_row] = true; + line(m_cursor_row).needs_invalidation = true; if (m_belling) { m_need_full_invalidation = true; @@ -568,7 +577,7 @@ void Terminal::paint() Rect invalidation_rect; for (int i = 0; i < m_rows; ++i) { - if (m_row_needs_invalidation[i]) + if (line(i).needs_invalidation) invalidation_rect = invalidation_rect.united(row_rect(i)); } invalidate_window(invalidation_rect); diff --git a/Terminal/Terminal.h b/Terminal/Terminal.h index f3165a9a1e..d44bcb3e0c 100644 --- a/Terminal/Terminal.h +++ b/Terminal/Terminal.h @@ -61,9 +61,18 @@ private: bool dirty : 1; }; - byte* m_buffer { nullptr }; - Attribute* m_attributes { nullptr }; - bool* m_row_needs_invalidation { nullptr }; + struct Line { + explicit Line(word columns); + ~Line(); + void clear(); + byte* characters { nullptr }; + Attribute* attributes { nullptr }; + bool needs_invalidation { false }; + word length { 0 }; + }; + Line& line(size_t index) { ASSERT(index < m_rows); return *m_lines[index]; } + + Line** m_lines { nullptr }; word m_columns { 0 }; word m_rows { 0 }; diff --git a/Terminal/main.cpp b/Terminal/main.cpp index 05ffd932c7..1670e20458 100644 --- a/Terminal/main.cpp +++ b/Terminal/main.cpp @@ -93,6 +93,7 @@ int main(int, char**) byte buffer[1024]; ssize_t nread = read(ptm_fd, buffer, sizeof(buffer)); if (nread < 0) { + dbgprintf("Terminal read error: %s\n", strerror(errno)); perror("read(ptm)"); continue; }