summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndreas Kling <awesomekling@gmail.com>2019-02-20 23:32:33 +0100
committerAndreas Kling <awesomekling@gmail.com>2019-02-20 23:38:20 +0100
commit0aaec6b19abf1e6e2a9bcc9eca201f45adbb797f (patch)
tree3aa982f75e6d16f174f5b6c6a4b1adef290fef00
parent0ca311230162e07506832f4d74baeb96549606fc (diff)
downloadserenity-0aaec6b19abf1e6e2a9bcc9eca201f45adbb797f.zip
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. :^)
-rw-r--r--Applications/Terminal/Terminal.cpp65
-rw-r--r--Kernel/MasterPTY.cpp8
-rw-r--r--Kernel/MasterPTY.h1
-rw-r--r--Kernel/Process.cpp1
-rw-r--r--Kernel/TTY.cpp17
-rw-r--r--LibC/sys/ioctl_numbers.h1
6 files changed, 74 insertions, 19 deletions
diff --git a/Applications/Terminal/Terminal.cpp b/Applications/Terminal/Terminal.cpp
index 52130340a1..9407fdba06 100644
--- a/Applications/Terminal/Terminal.cpp
+++ b/Applications/Terminal/Terminal.cpp
@@ -13,6 +13,7 @@
#include <LibGUI/GApplication.h>
#include <LibGUI/GWindow.h>
#include <Kernel/KeyCode.h>
+#include <sys/ioctl.h>
//#define TERMINAL_DEBUG
@@ -45,21 +46,6 @@ Terminal::Terminal(int ptm_fd)
m_line_height = font().glyph_height() + m_line_spacing;
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)
@@ -596,8 +582,50 @@ void Terminal::unimplemented_xterm_escape()
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_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)
@@ -761,8 +789,9 @@ void Terminal::force_repaint()
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);
}
diff --git a/Kernel/MasterPTY.cpp b/Kernel/MasterPTY.cpp
index 73428d2828..d6af396576 100644
--- a/Kernel/MasterPTY.cpp
+++ b/Kernel/MasterPTY.cpp
@@ -4,6 +4,7 @@
#include <Kernel/Process.h>
#include <LibC/errno_numbers.h>
#include <LibC/signal_numbers.h>
+#include <LibC/sys/ioctl_numbers.h>
MasterPTY::MasterPTY(unsigned index)
: CharacterDevice(10, index)
@@ -87,3 +88,10 @@ void MasterPTY::close()
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;
+}
diff --git a/Kernel/MasterPTY.h b/Kernel/MasterPTY.h
index dfae451cd8..896f094bce 100644
--- a/Kernel/MasterPTY.h
+++ b/Kernel/MasterPTY.h
@@ -26,6 +26,7 @@ private:
virtual bool can_write(Process&) const override;
virtual void close() override;
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"; }
RetainPtr<SlavePTY> m_slave;
diff --git a/Kernel/Process.cpp b/Kernel/Process.cpp
index 5e7416b4df..f0ae095cea 100644
--- a/Kernel/Process.cpp
+++ b/Kernel/Process.cpp
@@ -1868,6 +1868,7 @@ void Process::set_default_signal_dispositions()
// FIXME: Set up all the right default actions. See signal(7).
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[SIGWINCH].handler_or_sigaction = LinearAddress((dword)SIG_IGN);
}
int Process::sys$sigaction(int signum, const sigaction* act, sigaction* old_act)
diff --git a/Kernel/TTY.cpp b/Kernel/TTY.cpp
index df119bcf25..afa3b98cd8 100644
--- a/Kernel/TTY.cpp
+++ b/Kernel/TTY.cpp
@@ -112,8 +112,13 @@ int TTY::ioctl(Process& process, unsigned request, unsigned arg)
termios* tp;
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;
+ }
+#endif
switch (request) {
case TIOCGPGRP:
return m_pgid;
@@ -145,6 +150,16 @@ int TTY::ioctl(Process& process, unsigned request, unsigned arg)
ws->ws_row = m_rows;
ws->ws_col = m_columns;
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:
process.set_tty(this);
return 0;
diff --git a/LibC/sys/ioctl_numbers.h b/LibC/sys/ioctl_numbers.h
index 1ed0a9c934..85edc5dbfe 100644
--- a/LibC/sys/ioctl_numbers.h
+++ b/LibC/sys/ioctl_numbers.h
@@ -10,5 +10,6 @@ enum IOCtlNumber {
TIOCGWINSZ,
TIOCSCTTY,
TIOCNOTTY,
+ TIOCSWINSZ,
};