diff options
Diffstat (limited to 'Applications')
-rw-r--r-- | Applications/Terminal/Terminal.cpp | 316 | ||||
-rw-r--r-- | Applications/Terminal/Terminal.h | 12 | ||||
-rw-r--r-- | Applications/Terminal/main.cpp | 1 |
3 files changed, 206 insertions, 123 deletions
diff --git a/Applications/Terminal/Terminal.cpp b/Applications/Terminal/Terminal.cpp index d4f70098b8..4bd21a9001 100644 --- a/Applications/Terminal/Terminal.cpp +++ b/Applications/Terminal/Terminal.cpp @@ -1,19 +1,19 @@ #include "Terminal.h" #include "XtermColors.h" -#include <string.h> -#include <errno.h> -#include <stdlib.h> -#include <unistd.h> -#include <stdio.h> #include <AK/AKString.h> -#include <AK/StringBuilder.h> -#include <SharedGraphics/Font.h> -#include <LibGUI/GPainter.h> #include <AK/StdLibExtras.h> +#include <AK/StringBuilder.h> +#include <Kernel/KeyCode.h> #include <LibGUI/GApplication.h> +#include <LibGUI/GPainter.h> #include <LibGUI/GWindow.h> -#include <Kernel/KeyCode.h> +#include <SharedGraphics/Font.h> +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> #include <sys/ioctl.h> +#include <unistd.h> //#define TERMINAL_DEBUG byte Terminal::Attribute::default_foreground_color = 7; @@ -30,8 +30,8 @@ Terminal::Terminal(int ptm_fd, RetainPtr<CConfigFile> config) dbgprintf("Terminal: Load config file from %s\n", m_config->file_name().characters()); m_cursor_blink_timer.set_interval(m_config->read_num_entry("Text", - "CursorBlinkInterval", - 500)); + "CursorBlinkInterval", + 500)); m_cursor_blink_timer.on_timeout = [this] { m_cursor_blink_state = !m_cursor_blink_state; update_cursor(); @@ -43,7 +43,7 @@ Terminal::Terminal(int ptm_fd, RetainPtr<CConfigFile> config) else set_font(Font::load_from_file(font_entry)); - m_notifier.on_ready_to_read = [this]{ + m_notifier.on_ready_to_read = [this] { byte buffer[BUFSIZ]; ssize_t nread = read(m_ptm_fd, buffer, sizeof(buffer)); if (nread < 0) { @@ -65,7 +65,7 @@ Terminal::Terminal(int ptm_fd, RetainPtr<CConfigFile> config) m_line_height = font().glyph_height() + m_line_spacing; set_size(m_config->read_num_entry("Window", "Width", 80), - m_config->read_num_entry("Window", "Height", 25)); + m_config->read_num_entry("Window", "Height", 25)); } Terminal::Line::Line(word columns) @@ -78,24 +78,24 @@ Terminal::Line::Line(word columns) Terminal::Line::~Line() { - delete [] characters; - delete [] attributes; + delete[] characters; + delete[] attributes; } void Terminal::Line::clear(Attribute attribute) { if (dirty) { memset(characters, ' ', length); - for (word i = 0 ; i < length; ++i) + for (word i = 0; i < length; ++i) attributes[i] = attribute; return; } - for (unsigned i = 0 ; i < length; ++i) { + for (unsigned i = 0; i < length; ++i) { if (characters[i] != ' ') dirty = true; characters[i] = ' '; } - for (unsigned i = 0 ; i < length; ++i) { + for (unsigned i = 0; i < length; ++i) { if (attributes[i] != attribute) dirty = true; attributes[i] = attribute; @@ -104,9 +104,6 @@ void Terminal::Line::clear(Attribute attribute) Terminal::~Terminal() { - for (int i = 0; i < m_rows; ++i) - delete m_lines[i]; - delete [] m_lines; free(m_horizontal_tabs); } @@ -137,6 +134,35 @@ static inline Color lookup_color(unsigned color) return Color::from_rgb(xterm_colors[color]); } +void Terminal::escape$h_l(bool should_set, bool question_param, const ParamVector& params) +{ + int mode = 2; + if (params.size() > 0) { + mode = params[0]; + } + if (!question_param) { + switch (mode) { + // FIXME: implement *something* for this + default: + unimplemented_escape(); + break; + } + } else { + switch (mode) { + case 25: + // Hide cursor command, but doesn't need to be run (for now, because + // we don't do inverse control codes anyways) + if (should_set) + dbgprintf("Terminal: Hide Cursor escapecode recieved. Not needed: ignored.\n"); + else + dbgprintf("Terminal: Show Cursor escapecode recieved. Not needed: ignored.\n"); + break; + default: + break; + } + } +} + void Terminal::escape$m(const ParamVector& params) { if (params.is_empty()) { @@ -243,7 +269,7 @@ void Terminal::escape$t(const ParamVector& params) { if (params.size() < 1) return; - dbgprintf("FIXME: escape$t: Ps: %u\n", params[0]); + dbgprintf("FIXME: escape$t: Ps: %u (param count: %d)\n", params[0], params.size()); } void Terminal::escape$r(const ParamVector& params) @@ -254,12 +280,12 @@ void Terminal::escape$r(const ParamVector& params) top = params[0]; if (params.size() >= 2) bottom = params[1]; - if ((bottom - top) < 2 || bottom > m_rows) { - dbgprintf("Error: escape: scrolling region invalid: %u-%u\n", top, bottom); + if ((bottom - top) < 2 || bottom > m_rows || top < 0) { + dbgprintf("Error: escape$r: scrolling region invalid: %u-%u\n", top, bottom); return; } - m_scroll_region_top = top; - m_scroll_region_bottom = bottom; + m_scroll_region_top = top - 1; + m_scroll_region_bottom = bottom - 1; set_cursor(0, 0); } @@ -379,7 +405,10 @@ void Terminal::escape$K(const ParamVector& params) } break; case 2: - unimplemented_escape(); + // Clear the complete line + for (int i = 0; i < m_columns; ++i) { + put_character_at(m_cursor_row, i, ' '); + } break; default: unimplemented_escape(); @@ -395,9 +424,8 @@ void Terminal::escape$J(const ParamVector& params) switch (mode) { case 0: // Clear from cursor to end of screen. - for (int i = m_cursor_column; i < m_columns; ++i) { + for (int i = m_cursor_column; i < m_columns; ++i) put_character_at(m_cursor_row, i, ' '); - } for (int row = m_cursor_row + 1; row < m_rows; ++row) { for (int column = 0; column < m_columns; ++column) { put_character_at(row, column, ' '); @@ -405,8 +433,14 @@ void Terminal::escape$J(const ParamVector& params) } break; case 1: - // FIXME: Clear from cursor to beginning of screen. - unimplemented_escape(); + /// Clear from cursor to beginning of screen + for (int i = m_cursor_column - 1; i >= 0; --i) + put_character_at(m_cursor_row, i, ' '); + for (int row = m_cursor_row - 1; row >= 0; --row) { + for (int column = 0; column < m_columns; ++column) { + put_character_at(row, column, ' '); + } + } break; case 2: clear(); @@ -426,7 +460,6 @@ void Terminal::escape$S(const ParamVector& params) int count = 1; if (params.size() >= 1) count = params[0]; - dbgprintf("Terminal: Scrolling up %d lines\n", count); for (word i = 0; i < count; i++) scroll_up(); @@ -437,7 +470,6 @@ void Terminal::escape$T(const ParamVector& params) int count = 1; if (params.size() >= 1) count = params[0]; - dbgprintf("Terminal: Scrolling down %d lines\n", count); for (word i = 0; i < count; i++) scroll_down(); @@ -448,12 +480,14 @@ void Terminal::escape$L(const ParamVector& params) int count = 1; if (params.size() >= 1) count = params[0]; - dbgprintf("Terminal: Adding %d lines below cursor (at line %d)\n", count, m_cursor_row); invalidate_cursor(); - for (word row = m_rows; row > m_cursor_row; --row) - m_lines[row] = m_lines[row - 1]; - m_lines[m_cursor_row] = new Line(m_columns); - ++m_rows_to_scroll_backing_store; + for (; count > 0; --count) { + m_lines.insert(m_cursor_row + m_scroll_region_top, make<Line>(m_columns)); + if (m_scroll_region_bottom + 1 < m_lines.size()) + m_lines.remove(m_scroll_region_bottom + 1); + else + m_lines.remove(m_lines.size() - 1); + } m_need_full_flush = true; } @@ -468,15 +502,16 @@ void Terminal::escape$M(const ParamVector& params) return; } - int max_count = m_rows - m_cursor_row; + int max_count = m_rows - (m_scroll_region_top + m_cursor_row); count = min(count, max_count); - dbgprintf("Delete %d line(s) starting from %d\n", count, m_cursor_row); - for (word i = 0; i < count; ++i) - delete m_lines[m_cursor_row + i]; - for (word row = m_cursor_row + count + 1; row < rows(); ++row) - m_lines[row - 1] = m_lines[row]; - m_lines[m_rows - 1]->clear(m_current_attribute); + for (int c = count; c > 0; --c) { + m_lines.remove(m_cursor_row + m_scroll_region_top); + if (m_scroll_region_bottom < m_lines.size()) + m_lines.insert(m_scroll_region_bottom, make<Line>(m_columns)); + else + m_lines.append(make<Line>(m_columns)); + } } void Terminal::execute_xterm_command() @@ -502,45 +537,116 @@ void Terminal::execute_xterm_command() void Terminal::execute_escape_sequence(byte final) { + bool question_param = false; m_final = final; - auto paramparts = String::copy(m_parameters).split(';'); ParamVector params; + + if (m_parameters.size() > 0 && m_parameters[0] == '?') { + question_param = true; + m_parameters.remove(0); + } + auto paramparts = String::copy(m_parameters).split(';'); for (auto& parampart : paramparts) { bool ok; unsigned value = parampart.to_uint(ok); if (!ok) { + // FIXME: Should we do something else? m_parameters.clear_with_capacity(); m_intermediates.clear_with_capacity(); - // FIXME: Should we do something else? return; } params.append(value); } + +#if defined(TERMINAL_DEBUG) + dbgprintf("Terminal::execute_escape_sequence: Handled final '%c'\n", final); + dbgprintf("Params: "); + for (auto& p : params) { + dbgprintf("%d ", p); + } + dbgprintf("\b\n"); +#endif + switch (final) { - case 'A': escape$A(params); break; - case 'B': escape$B(params); break; - case 'C': escape$C(params); break; - case 'D': escape$D(params); break; - case 'H': escape$H(params); break; - case 'J': escape$J(params); break; - case 'K': escape$K(params); break; - case 'M': escape$M(params); break; - case 'S': escape$S(params); break; - case 'T': escape$T(params); break; - case 'L': escape$L(params); break; - case 'G': escape$G(params); break; - case 'X': escape$X(params); break; - case 'd': escape$d(params); break; - case 'm': escape$m(params); break; - case 's': escape$s(params); break; - case 'u': escape$u(params); break; - case 't': escape$t(params); break; - case 'r': escape$r(params); break; + case 'A': + escape$A(params); + break; + case 'B': + escape$B(params); + break; + case 'C': + escape$C(params); + break; + case 'D': + escape$D(params); + break; + case 'H': + escape$H(params); + break; + case 'J': + escape$J(params); + break; + case 'K': + escape$K(params); + break; + case 'M': + escape$M(params); + break; + case 'S': + escape$S(params); + break; + case 'T': + escape$T(params); + break; + case 'L': + escape$L(params); + break; + case 'G': + escape$G(params); + break; + case 'X': + escape$X(params); + break; + case 'd': + escape$d(params); + break; + case 'm': + escape$m(params); + break; + case 's': + escape$s(params); + break; + case 'u': + escape$u(params); + break; + case 't': + escape$t(params); + break; + case 'r': + escape$r(params); + break; + case 'l': + escape$h_l(true, question_param, params); + break; + case 'h': + escape$h_l(false, question_param, params); + break; default: dbgprintf("Terminal::execute_escape_sequence: Unhandled final '%c'\n", final); break; } +#if defined(TERMINAL_DEBUG) + dbgprintf("\n"); + for (auto& line : m_lines) { + dbgprintf("Terminal: Line: "); + for (int i = 0; i < line->length; i++) { + dbgprintf("%c", line->characters[i]); + } + dbgprintf("\n"); + } +#endif + m_parameters.clear_with_capacity(); m_intermediates.clear_with_capacity(); } @@ -548,7 +654,7 @@ void Terminal::execute_escape_sequence(byte final) void Terminal::newline() { word new_row = m_cursor_row; - if (m_cursor_row == (rows() - 1)) { + if (m_cursor_row == m_scroll_region_bottom) { scroll_up(); } else { ++new_row; @@ -560,11 +666,8 @@ void Terminal::scroll_up() { // NOTE: We have to invalidate the cursor first. invalidate_cursor(); - delete m_lines[m_scroll_region_top]; - for (word row = m_scroll_region_top + 1; row < m_scroll_region_bottom; ++row) - m_lines[row - 1] = m_lines[row]; - m_lines[m_scroll_region_bottom - 1] = new Line(m_columns); - ++m_rows_to_scroll_backing_store; + m_lines.remove(m_scroll_region_top); + m_lines.insert(m_scroll_region_bottom, make<Line>(m_columns)); m_need_full_flush = true; } @@ -572,10 +675,8 @@ void Terminal::scroll_down() { // NOTE: We have to invalidate the cursor first. invalidate_cursor(); - for (word row = m_scroll_region_bottom; row > m_scroll_region_top; --row) - m_lines[row] = m_lines[row - 1]; - m_lines[m_scroll_region_top] = new Line(m_columns); - --m_rows_to_scroll_backing_store; + m_lines.remove(m_scroll_region_bottom); + m_lines.insert(m_scroll_region_top, make<Line>(m_columns)); m_need_full_flush = true; } @@ -590,7 +691,7 @@ void Terminal::set_cursor(unsigned a_row, unsigned a_column) invalidate_cursor(); m_cursor_row = row; m_cursor_column = column; - if (column != columns() - 1) + if (column != columns() - 1u) m_stomp = false; invalidate_cursor(); } @@ -600,8 +701,6 @@ void Terminal::put_character_at(unsigned row, unsigned column, byte ch) ASSERT(row < rows()); ASSERT(column < columns()); auto& line = this->line(row); - if ((line.characters[column] == ch) && (line.attributes[column] == m_current_attribute)) - return; line.characters[column] = ch; line.attributes[column] = m_current_attribute; line.dirty = true; @@ -693,8 +792,8 @@ void Terminal::on_char(byte ch) m_visual_beep_timer.restart(200); m_visual_beep_timer.set_single_shot(true); m_visual_beep_timer.on_timeout = [this] { - force_repaint(); - }; + force_repaint(); + }; force_repaint(); } return; @@ -768,17 +867,22 @@ void Terminal::set_size(word columns, word rows) if (columns == m_columns && rows == m_rows) return; - if (m_lines) { - for (size_t i = 0; i < m_rows; ++i) - delete m_lines[i]; - delete m_lines; +#if defined(TERMINAL_DEBUG) + dbgprintf("Terminal: RESIZE to: %d rows\n", rows); +#endif + + if (rows > m_rows) { + while (m_lines.size() < rows) + m_lines.append(make<Line>(columns)); + } else { + m_lines.resize(rows); } m_columns = columns; m_rows = rows; m_scroll_region_top = 0; - m_scroll_region_bottom = rows; + m_scroll_region_bottom = rows - 1; m_cursor_row = 0; m_cursor_column = 0; @@ -793,17 +897,12 @@ void Terminal::set_size(word columns, word rows) // Rightmost column is always last tab on line. m_horizontal_tabs[columns - 1] = 1; - m_lines = new Line*[rows]; - for (size_t i = 0; i < rows; ++i) - m_lines[i] = new Line(columns); - m_pixel_width = (frame_thickness() * 2) + (m_inset * 2) + (m_columns * font().glyph_width('x')); m_pixel_height = (frame_thickness() * 2) + (m_inset * 2) + (m_rows * (font().glyph_height() + m_line_spacing)) - m_line_spacing; set_size_policy(SizePolicy::Fixed, SizePolicy::Fixed); set_preferred_size({ m_pixel_width, m_pixel_height }); - m_rows_to_scroll_backing_store = 0; m_needs_background_fill = true; force_repaint(); @@ -888,7 +987,9 @@ void Terminal::keydown_event(GKeyEvent& event) write(m_ptm_fd, "\033[F", 3); break; case KeyCode::Key_RightShift: - dbgprintf("Terminal: A wild Right Shift key is pressed. Not handled.\n"); + // Prevent RightShift from being sent to whatever's running in the + // terminal. Prevents `~@` (null) character from being sent after every + // character entered with right shift. break; default: write(m_ptm_fd, &ch, 1); @@ -902,44 +1003,23 @@ void Terminal::paint_event(GPaintEvent& event) GPainter painter(*this); - if (m_needs_background_fill) { - m_needs_background_fill = false; - if (m_visual_beep_timer.is_active()) - painter.fill_rect(frame_inner_rect(), Color::Red); - else - painter.fill_rect(frame_inner_rect(), Color(Color::Black).with_alpha(255 * m_opacity)); - } - - 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); - 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; - memcpy( - painter.target()->scanline(first_scanline), - painter.target()->scanline(second_scanline), - scanlines_to_copy * painter.target()->pitch() - ); - line(max(0, m_cursor_row - m_rows_to_scroll_backing_store)).dirty = true; - } - m_rows_to_scroll_backing_store = 0; - + if (m_visual_beep_timer.is_active()) + painter.fill_rect(frame_inner_rect(), Color::Red); + else + painter.fill_rect(frame_inner_rect(), Color(Color::Black).with_alpha(255 * m_opacity)); invalidate_cursor(); for (word row = 0; row < m_rows; ++row) { auto& line = this->line(row); - if (!line.dirty) - continue; - line.dirty = false; bool has_only_one_background_color = line.has_only_one_background_color(); if (m_visual_beep_timer.is_active()) painter.fill_rect(row_rect(row), Color::Red); else if (has_only_one_background_color) painter.fill_rect(row_rect(row), lookup_color(line.attributes[0].background_color).with_alpha(255 * m_opacity)); for (word column = 0; column < m_columns; ++column) { + char ch = line.characters[column]; bool should_reverse_fill_for_cursor = m_cursor_blink_state && m_in_active_window && row == m_cursor_row && column == m_cursor_column; auto& attribute = line.attributes[column]; - char ch = line.characters[column]; auto character_rect = glyph_rect(row, column); if (!has_only_one_background_color || should_reverse_fill_for_cursor) { auto cell_rect = character_rect.inflated(0, m_line_spacing); diff --git a/Applications/Terminal/Terminal.h b/Applications/Terminal/Terminal.h index 137e68569b..82d13a546f 100644 --- a/Applications/Terminal/Terminal.h +++ b/Applications/Terminal/Terminal.h @@ -72,6 +72,7 @@ private: void escape$S(const ParamVector&); void escape$T(const ParamVector&); void escape$L(const ParamVector&); + void escape$h_l(bool, bool, const ParamVector&); void clear(); @@ -97,7 +98,8 @@ private: byte foreground_color; byte background_color; - enum Flags { + enum Flags + { NoAttributes = 0x00, Bold = 0x01, Italic = 0x02, @@ -136,7 +138,10 @@ private: return *m_lines[index]; } - Line** m_lines { nullptr }; + Vector<OwnPtr<Line>> m_lines; + + int m_scroll_region_top { 0 }; + int m_scroll_region_bottom { 0 }; word m_columns { 0 }; word m_rows { 0 }; @@ -148,8 +153,6 @@ private: bool m_stomp { false }; bool m_should_beep { false }; - byte m_scroll_region_top { 0 }; - byte m_scroll_region_bottom { 0 }; Attribute m_current_attribute; @@ -179,7 +182,6 @@ private: int m_pixel_width { 0 }; int m_pixel_height { 0 }; - int m_rows_to_scroll_backing_store { 0 }; int m_inset { 2 }; int m_line_spacing { 4 }; diff --git a/Applications/Terminal/main.cpp b/Applications/Terminal/main.cpp index ee364af217..dfae564599 100644 --- a/Applications/Terminal/main.cpp +++ b/Applications/Terminal/main.cpp @@ -20,6 +20,7 @@ #include <LibGUI/GAction.h> #include <LibGUI/GFontDatabase.h> #include <LibGUI/GSlider.h> +#include <LibGUI/GRadioButton.h> #include <LibCore/CUserInfo.h> static void make_shell(int ptm_fd) |