瀏覽代碼

Support resizing the Terminal app.

I set it up so that TIOCSWINSZ on a master PTY gets forwarded to the slave.
This feels intuitively right. Terminal can then use that to inform the shell
or whoever is inside the slave that the window size has changed.

TIOCSWINSZ also triggers the generation of a SIGWINCH signal. :^)
Andreas Kling 6 年之前
父節點
當前提交
0aaec6b19a
共有 6 個文件被更改,包括 74 次插入19 次删除
  1. 47 18
      Applications/Terminal/Terminal.cpp
  2. 8 0
      Kernel/MasterPTY.cpp
  3. 1 0
      Kernel/MasterPTY.h
  4. 1 0
      Kernel/Process.cpp
  5. 16 1
      Kernel/TTY.cpp
  6. 1 0
      LibC/sys/ioctl_numbers.h

+ 47 - 18
Applications/Terminal/Terminal.cpp

@@ -13,6 +13,7 @@
 #include <LibGUI/GApplication.h>
 #include <LibGUI/GApplication.h>
 #include <LibGUI/GWindow.h>
 #include <LibGUI/GWindow.h>
 #include <Kernel/KeyCode.h>
 #include <Kernel/KeyCode.h>
+#include <sys/ioctl.h>
 
 
 //#define TERMINAL_DEBUG
 //#define TERMINAL_DEBUG
 
 
@@ -45,21 +46,6 @@ Terminal::Terminal(int ptm_fd)
     m_line_height = font().glyph_height() + m_line_spacing;
     m_line_height = font().glyph_height() + m_line_spacing;
 
 
     set_size(80, 25);
     set_size(80, 25);
-    m_horizontal_tabs = static_cast<byte*>(malloc(columns()));
-    for (unsigned i = 0; i < columns(); ++i)
-        m_horizontal_tabs[i] = (i % 8) == 0;
-    // 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 = 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)
 Terminal::Line::Line(word columns)
@@ -596,8 +582,50 @@ void Terminal::unimplemented_xterm_escape()
 
 
 void Terminal::set_size(word columns, word rows)
 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;
+    }
+
     m_columns = columns;
     m_columns = columns;
     m_rows = rows;
     m_rows = rows;
+
+    m_cursor_row = 0;
+    m_cursor_column = 0;
+    m_saved_cursor_row = 0;
+    m_saved_cursor_column = 0;
+
+    if (m_horizontal_tabs)
+        free(m_horizontal_tabs);
+    m_horizontal_tabs = static_cast<byte*>(malloc(columns));
+    for (unsigned i = 0; i < columns; ++i)
+        m_horizontal_tabs[i] = (i % 8) == 0;
+    // 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 = 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 });
+
+    m_rows_to_scroll_backing_store = 0;
+    m_needs_background_fill = true;
+    force_repaint();
+
+    winsize ws;
+    ws.ws_row = rows;
+    ws.ws_col = columns;
+    int rc = ioctl(m_ptm_fd, TIOCSWINSZ, &ws);
+    ASSERT(rc == 0);
 }
 }
 
 
 Rect Terminal::glyph_rect(word row, word column)
 Rect Terminal::glyph_rect(word row, word column)
@@ -761,8 +789,9 @@ void Terminal::force_repaint()
     update();
     update();
 }
 }
 
 
-void Terminal::resize_event(GResizeEvent&)
+void Terminal::resize_event(GResizeEvent& event)
 {
 {
-    m_needs_background_fill = true;
-    force_repaint();
+    int new_columns = event.size().width() / m_font->glyph_width();
+    int new_rows = event.size().height() / m_line_height;
+    set_size(new_columns, new_rows);
 }
 }

+ 8 - 0
Kernel/MasterPTY.cpp

@@ -4,6 +4,7 @@
 #include <Kernel/Process.h>
 #include <Kernel/Process.h>
 #include <LibC/errno_numbers.h>
 #include <LibC/errno_numbers.h>
 #include <LibC/signal_numbers.h>
 #include <LibC/signal_numbers.h>
+#include <LibC/sys/ioctl_numbers.h>
 
 
 MasterPTY::MasterPTY(unsigned index)
 MasterPTY::MasterPTY(unsigned index)
     : CharacterDevice(10, index)
     : CharacterDevice(10, index)
@@ -87,3 +88,10 @@ void MasterPTY::close()
         m_slave->hang_up();
         m_slave->hang_up();
     }
     }
 }
 }
+
+int MasterPTY::ioctl(Process& process, unsigned request, unsigned arg)
+{
+    if (request == TIOCSWINSZ)
+        return m_slave->ioctl(process, request, arg);
+    return -EINVAL;
+}

+ 1 - 0
Kernel/MasterPTY.h

@@ -26,6 +26,7 @@ private:
     virtual bool can_write(Process&) const override;
     virtual bool can_write(Process&) const override;
     virtual void close() override;
     virtual void close() override;
     virtual bool is_master_pty() const override { return true; }
     virtual bool is_master_pty() const override { return true; }
+    virtual int ioctl(Process&, unsigned request, unsigned arg) override;
     virtual const char* class_name() const override { return "MasterPTY"; }
     virtual const char* class_name() const override { return "MasterPTY"; }
 
 
     RetainPtr<SlavePTY> m_slave;
     RetainPtr<SlavePTY> m_slave;

+ 1 - 0
Kernel/Process.cpp

@@ -1868,6 +1868,7 @@ void Process::set_default_signal_dispositions()
     // FIXME: Set up all the right default actions. See signal(7).
     // FIXME: Set up all the right default actions. See signal(7).
     memset(&m_signal_action_data, 0, sizeof(m_signal_action_data));
     memset(&m_signal_action_data, 0, sizeof(m_signal_action_data));
     m_signal_action_data[SIGCHLD].handler_or_sigaction = LinearAddress((dword)SIG_IGN);
     m_signal_action_data[SIGCHLD].handler_or_sigaction = LinearAddress((dword)SIG_IGN);
+    m_signal_action_data[SIGWINCH].handler_or_sigaction = LinearAddress((dword)SIG_IGN);
 }
 }
 
 
 int Process::sys$sigaction(int signum, const sigaction* act, sigaction* old_act)
 int Process::sys$sigaction(int signum, const sigaction* act, sigaction* old_act)

+ 16 - 1
Kernel/TTY.cpp

@@ -112,8 +112,13 @@ int TTY::ioctl(Process& process, unsigned request, unsigned arg)
     termios* tp;
     termios* tp;
     winsize* ws;
     winsize* ws;
 
 
-    if (process.tty() && process.tty() != this)
+#if 0
+    // FIXME: When should we block things?
+    //        How do we make this work together with MasterPTY forwarding to us?
+    if (process.tty() && process.tty() != this) {
         return -ENOTTY;
         return -ENOTTY;
+    }
+#endif
     switch (request) {
     switch (request) {
     case TIOCGPGRP:
     case TIOCGPGRP:
         return m_pgid;
         return m_pgid;
@@ -145,6 +150,16 @@ int TTY::ioctl(Process& process, unsigned request, unsigned arg)
         ws->ws_row = m_rows;
         ws->ws_row = m_rows;
         ws->ws_col = m_columns;
         ws->ws_col = m_columns;
         return 0;
         return 0;
+    case TIOCSWINSZ:
+        ws = reinterpret_cast<winsize*>(arg);
+        if (!process.validate_read(ws, sizeof(winsize)))
+            return -EFAULT;
+        if (ws->ws_col == m_columns && ws->ws_row == m_rows)
+            return 0;
+        m_rows = ws->ws_row;
+        m_columns = ws->ws_col;
+        generate_signal(SIGWINCH);
+        return 0;
     case TIOCSCTTY:
     case TIOCSCTTY:
         process.set_tty(this);
         process.set_tty(this);
         return 0;
         return 0;

+ 1 - 0
LibC/sys/ioctl_numbers.h

@@ -10,5 +10,6 @@ enum IOCtlNumber {
     TIOCGWINSZ,
     TIOCGWINSZ,
     TIOCSCTTY,
     TIOCSCTTY,
     TIOCNOTTY,
     TIOCNOTTY,
+    TIOCSWINSZ,
 };
 };