diff options
Diffstat (limited to 'Userland')
-rw-r--r-- | Userland/Libraries/LibVT/Terminal.cpp | 93 | ||||
-rw-r--r-- | Userland/Libraries/LibVT/Terminal.h | 17 | ||||
-rw-r--r-- | Userland/Libraries/LibVT/TerminalWidget.cpp | 57 | ||||
-rw-r--r-- | Userland/Libraries/LibVT/TerminalWidget.h | 3 |
4 files changed, 156 insertions, 14 deletions
diff --git a/Userland/Libraries/LibVT/Terminal.cpp b/Userland/Libraries/LibVT/Terminal.cpp index 2fc319be28..6e4575df4d 100644 --- a/Userland/Libraries/LibVT/Terminal.cpp +++ b/Userland/Libraries/LibVT/Terminal.cpp @@ -46,24 +46,64 @@ void Terminal::clear_including_history() void Terminal::alter_mode(bool should_set, Parameters params, Intermediates intermediates) { + auto steady_cursor_to_blinking = [](CursorStyle style) { + switch (style) { + case SteadyBar: + return BlinkingBar; + case SteadyBlock: + return BlinkingBlock; + case SteadyUnderline: + return BlinkingUnderline; + default: + return style; + } + }; + + auto blinking_cursor_to_steady = [](CursorStyle style) { + switch (style) { + case BlinkingBar: + return SteadyBar; + case BlinkingBlock: + return SteadyBlock; + case BlinkingUnderline: + return SteadyUnderline; + default: + return style; + } + }; + if (intermediates.size() > 0 && intermediates[0] == '?') { for (auto mode : params) { switch (mode) { case 3: { // 80/132-column mode (DECCOLM) - unsigned new_columns = should_set ? 80 : 132; + unsigned new_columns = should_set ? 132 : 80; dbgln_if(TERMINAL_DEBUG, "Setting {}-column mode", new_columns); set_size(new_columns, rows()); clear(); break; } + case 12: + if (should_set) { + // Start blinking cursor + m_cursor_style = steady_cursor_to_blinking(m_cursor_style); + } else { + // Stop blinking cursor + m_cursor_style = blinking_cursor_to_steady(m_cursor_style); + } + m_client.set_cursor_style(m_cursor_style); + break; 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) - dbgln("Terminal: Hide Cursor escapecode received. Not needed: ignored."); - else - dbgln("Terminal: Show Cursor escapecode received. Not needed: ignored."); + if (should_set) { + // Show cursor + m_cursor_style = m_saved_cursor_style; + m_client.set_cursor_style(m_cursor_style); + } else { + // Hide cursor + m_saved_cursor_style = m_cursor_style; + m_cursor_style = None; + m_client.set_cursor_style(None); + } break; default: dbgln("Terminal::alter_mode: Unimplemented private mode {} (should_set={})", mode, should_set); @@ -84,12 +124,12 @@ void Terminal::alter_mode(bool should_set, Parameters params, Intermediates inte void Terminal::RM(Parameters params, Intermediates intermediates) { - alter_mode(true, params, intermediates); + alter_mode(false, params, intermediates); } void Terminal::SM(Parameters params, Intermediates intermediates) { - alter_mode(false, params, intermediates); + alter_mode(true, params, intermediates); } void Terminal::SGR(Parameters params) @@ -454,6 +494,35 @@ void Terminal::SD(Parameters params) scroll_down(); } +void Terminal::DECSCUSR(Parameters params) +{ + unsigned style = 1; + if (params.size() >= 1 && params[0] != 0) + style = params[0]; + switch (style) { + case 1: + m_client.set_cursor_style(BlinkingBlock); + break; + case 2: + m_client.set_cursor_style(SteadyBlock); + break; + case 3: + m_client.set_cursor_style(BlinkingUnderline); + break; + case 4: + m_client.set_cursor_style(SteadyUnderline); + break; + case 5: + m_client.set_cursor_style(BlinkingBar); + break; + case 6: + m_client.set_cursor_style(SteadyBar); + break; + default: + dbgln("Unknown cursor style {}", style); + } +} + #ifndef KERNEL void Terminal::IL(Parameters params) { @@ -833,6 +902,12 @@ void Terminal::execute_csi_sequence(Parameters parameters, Intermediates interme case 'n': DSR(parameters); break; + case 'q': + if (intermediates.size() >= 1 && intermediates[0] == ' ') + DECSCUSR(parameters); + else + unimplemented_csi_sequence(parameters, intermediates, last_byte); + break; default: unimplemented_csi_sequence(parameters, intermediates, last_byte); } diff --git a/Userland/Libraries/LibVT/Terminal.h b/Userland/Libraries/LibVT/Terminal.h index f5d8560013..3ede089c27 100644 --- a/Userland/Libraries/LibVT/Terminal.h +++ b/Userland/Libraries/LibVT/Terminal.h @@ -26,6 +26,16 @@ class VirtualConsole; namespace VT { +enum CursorStyle { + None, + BlinkingBlock, + SteadyBlock, + BlinkingUnderline, + SteadyUnderline, + BlinkingBar, + SteadyBar +}; + class TerminalClient { public: virtual ~TerminalClient() { } @@ -36,6 +46,7 @@ public: virtual void terminal_did_resize(u16 columns, u16 rows) = 0; virtual void terminal_history_changed() = 0; virtual void emit(const u8*, size_t) = 0; + virtual void set_cursor_style(CursorStyle) = 0; }; class Terminal : public EscapeSequenceExecutor { @@ -238,6 +249,9 @@ protected: // DSR - Device Status Reports void DSR(Parameters); + // DECSCUSR - Set Cursor Style + void DECSCUSR(Parameters); + #ifndef KERNEL // ICH - Insert Character void ICH(Parameters); @@ -319,6 +333,9 @@ protected: bool m_swallow_current { false }; bool m_stomp { false }; + CursorStyle m_cursor_style { BlinkingBlock }; + CursorStyle m_saved_cursor_style { BlinkingBlock }; + Attribute m_current_attribute; Attribute m_saved_attribute; diff --git a/Userland/Libraries/LibVT/TerminalWidget.cpp b/Userland/Libraries/LibVT/TerminalWidget.cpp index dc3cc504a4..432ff28df2 100644 --- a/Userland/Libraries/LibVT/TerminalWidget.cpp +++ b/Userland/Libraries/LibVT/TerminalWidget.cpp @@ -326,6 +326,7 @@ void TerminalWidget::paint_event(GUI::PaintEvent& event) for (size_t column = 0; column < line.length(); ++column) { bool should_reverse_fill_for_cursor_or_selection = m_cursor_blink_state + && (m_cursor_style == VT::CursorStyle::SteadyBlock || m_cursor_style == VT::CursorStyle::BlinkingBlock) && m_has_logical_focus && visual_row == row_with_cursor && column == m_terminal.cursor_column(); @@ -392,6 +393,7 @@ void TerminalWidget::paint_event(GUI::PaintEvent& event) for (size_t column = 0; column < line.length(); ++column) { auto attribute = line.attribute_at(column); bool should_reverse_fill_for_cursor_or_selection = m_cursor_blink_state + && (m_cursor_style == VT::CursorStyle::SteadyBlock || m_cursor_style == VT::CursorStyle::BlinkingBlock) && m_has_logical_focus && visual_row == row_with_cursor && column == m_terminal.cursor_column(); @@ -417,11 +419,31 @@ void TerminalWidget::paint_event(GUI::PaintEvent& event) } // Draw cursor. - if (!m_has_logical_focus && row_with_cursor < m_terminal.rows()) { + if (m_cursor_blink_state && row_with_cursor < m_terminal.rows()) { auto& cursor_line = m_terminal.line(first_row_from_history + row_with_cursor); - if (m_terminal.cursor_row() < (m_terminal.rows() - rows_from_history)) { - auto cell_rect = glyph_rect(row_with_cursor, m_terminal.cursor_column()).inflated(0, m_line_spacing); - painter.draw_rect(cell_rect, color_from_rgb(cursor_line.attribute_at(m_terminal.cursor_column()).effective_foreground_color())); + if (m_terminal.cursor_row() >= (m_terminal.rows() - rows_from_history)) + return; + + if (m_has_logical_focus && (m_cursor_style == VT::CursorStyle::BlinkingBlock || m_cursor_style == VT::CursorStyle::SteadyBlock)) + return; // This has already been handled by inverting the cell colors + + auto cursor_color = color_from_rgb(cursor_line.attribute_at(m_terminal.cursor_column()).effective_foreground_color()); + auto cell_rect = glyph_rect(row_with_cursor, m_terminal.cursor_column()).inflated(0, m_line_spacing); + if (m_cursor_style == VT::CursorStyle::BlinkingUnderline || m_cursor_style == VT::CursorStyle::SteadyUnderline) { + auto x1 = cell_rect.bottom_left().x(); + auto x2 = cell_rect.bottom_right().x(); + auto y = cell_rect.bottom_left().y(); + for (auto x = x1; x <= x2; ++x) + painter.set_pixel({ x, y }, cursor_color); + } else if (m_cursor_style == VT::CursorStyle::BlinkingBar || m_cursor_style == VT::CursorStyle::SteadyBar) { + auto x = cell_rect.bottom_left().x(); + auto y1 = cell_rect.top_left().y(); + auto y2 = cell_rect.bottom_left().y(); + for (auto y = y1; y <= y2; ++y) + painter.set_pixel({ x, y }, cursor_color); + } else { + // We fall back to a block if we don't support the selected cursor type. + painter.draw_rect(cell_rect, cursor_color); } } } @@ -986,6 +1008,32 @@ void TerminalWidget::emit(const u8* data, size_t size) } } +void TerminalWidget::set_cursor_style(CursorStyle style) +{ + switch (style) { + case None: + m_cursor_blink_timer->stop(); + m_cursor_blink_state = false; + break; + case SteadyBlock: + case SteadyUnderline: + case SteadyBar: + m_cursor_blink_timer->stop(); + m_cursor_blink_state = true; + break; + case BlinkingBlock: + case BlinkingUnderline: + case BlinkingBar: + m_cursor_blink_state = true; + m_cursor_blink_timer->restart(); + break; + default: + dbgln("Cursor style not implemented"); + } + m_cursor_style = style; + invalidate_cursor(); +} + void TerminalWidget::context_menu_event(GUI::ContextMenuEvent& event) { if (m_hovered_href_id.is_null()) { @@ -1107,5 +1155,4 @@ void TerminalWidget::set_font_and_resize_to_fit(const Gfx::Font& font) set_font(font); resize(widget_size_for_font(font)); } - } diff --git a/Userland/Libraries/LibVT/TerminalWidget.h b/Userland/Libraries/LibVT/TerminalWidget.h index 81455da489..8e1e2fc790 100644 --- a/Userland/Libraries/LibVT/TerminalWidget.h +++ b/Userland/Libraries/LibVT/TerminalWidget.h @@ -114,6 +114,7 @@ private: virtual void terminal_did_resize(u16 columns, u16 rows) override; virtual void terminal_history_changed() override; virtual void emit(const u8*, size_t) override; + virtual void set_cursor_style(CursorStyle) override; void set_logical_focus(bool); @@ -173,6 +174,8 @@ private: bool m_cursor_blink_state { true }; bool m_automatic_size_policy { false }; + VT::CursorStyle m_cursor_style { BlinkingBlock }; + enum class AutoScrollDirection { None, Up, |