浏览代码

Terminal: Use Vectors and OwnPtrs for Terminal lines. Adjust scroll
region behavior

Christopher Dumas 6 年之前
父节点
当前提交
e92fe52031
共有 5 个文件被更改,包括 207 次插入126 次删除
  1. 198 118
      Applications/Terminal/Terminal.cpp
  2. 7 5
      Applications/Terminal/Terminal.h
  3. 1 0
      Applications/Terminal/main.cpp
  4. 1 0
      Kernel/.gitignore
  5. 0 3
      LibC/unistd.h

+ 198 - 118
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);

+ 7 - 5
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 };

+ 1 - 0
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)

+ 1 - 0
Kernel/.gitignore

@@ -8,3 +8,4 @@ sync-local.sh
 *.pcap
 eth_null*
 _disk_image
+compile_commmands.json

+ 0 - 3
LibC/unistd.h

@@ -109,7 +109,4 @@ enum
  */
 #define _POSIX_PRIORITY_SCHEDULING
 
-// Stifle an less error iirc
-#define _PC_VDISABLE 8
-
 __END_DECLS