LibVT+Terminal: Give TerminalWidget a hook for EOF on the pty

Instead of quitting the application immediately when the pty gives an
EOF, fire an on_command_exit hook so the TerminalWidget client can
decide for himself what to do.
This commit is contained in:
Andreas Kling 2019-10-22 21:57:53 +02:00
parent a6b153abf1
commit cd1eee6604
Notes: sideshowbarker 2024-07-19 11:35:11 +09:00
3 changed files with 52 additions and 23 deletions

View file

@ -163,6 +163,9 @@ int main(int argc, char** argv)
RefPtr<CConfigFile> config = CConfigFile::get_for_app("Terminal");
auto terminal = TerminalWidget::construct(ptm_fd, true, config);
terminal->on_command_exit = [&] {
app.quit(0);
};
terminal->on_title_change = [&](auto& title) {
window->set_title(title);
};

View file

@ -19,13 +19,46 @@
//#define TERMINAL_DEBUG
void TerminalWidget::set_pty_master_fd(int fd)
{
m_ptm_fd = fd;
if (m_ptm_fd == -1) {
m_notifier = nullptr;
return;
}
m_notifier = CNotifier::construct(m_ptm_fd, CNotifier::Read);
m_notifier->on_ready_to_read = [this] {
u8 buffer[BUFSIZ];
ssize_t nread = read(m_ptm_fd, buffer, sizeof(buffer));
if (nread < 0) {
dbgprintf("Terminal read error: %s\n", strerror(errno));
perror("read(ptm)");
GApplication::the().quit(1);
return;
}
if (nread == 0) {
dbgprintf("Terminal: EOF on master pty, firing on_command_exit hook.\n");
if (on_command_exit)
on_command_exit();
int rc = close(m_ptm_fd);
if (rc < 0) {
perror("close");
}
set_pty_master_fd(-1);
return;
}
for (ssize_t i = 0; i < nread; ++i)
m_terminal.on_char(buffer[i]);
flush_dirty_lines();
};
}
TerminalWidget::TerminalWidget(int ptm_fd, bool automatic_size_policy, RefPtr<CConfigFile> config)
: m_terminal(*this)
, m_ptm_fd(ptm_fd)
, m_notifier(CNotifier::construct(ptm_fd, CNotifier::Read))
, m_automatic_size_policy(automatic_size_policy)
, m_config(move(config))
{
set_pty_master_fd(ptm_fd);
m_cursor_blink_timer = CTimer::construct();
m_visual_beep_timer = CTimer::construct();
@ -54,25 +87,6 @@ TerminalWidget::TerminalWidget(int ptm_fd, bool automatic_size_policy, RefPtr<CC
else
set_font(Font::load_from_file(font_entry));
m_notifier->on_ready_to_read = [this] {
u8 buffer[BUFSIZ];
ssize_t nread = read(m_ptm_fd, buffer, sizeof(buffer));
if (nread < 0) {
dbgprintf("Terminal read error: %s\n", strerror(errno));
perror("read(ptm)");
GApplication::the().quit(1);
return;
}
if (nread == 0) {
dbgprintf("Terminal: EOF on master pty, closing.\n");
GApplication::the().quit(0);
return;
}
for (ssize_t i = 0; i < nread; ++i)
m_terminal.on_char(buffer[i]);
flush_dirty_lines();
};
m_line_height = font().glyph_height() + m_line_spacing;
m_terminal.set_size(m_config->read_num_entry("Window", "Width", 80), m_config->read_num_entry("Window", "Height", 25));
@ -138,6 +152,11 @@ void TerminalWidget::event(CEvent& event)
void TerminalWidget::keydown_event(GKeyEvent& event)
{
if (m_ptm_fd == -1) {
event.ignore();
return GFrame::keydown_event(event);
}
// Reset timer so cursor doesn't blink while typing.
m_cursor_blink_timer->stop();
m_cursor_blink_state = true;
@ -478,6 +497,8 @@ void TerminalWidget::mousedown_event(GMouseEvent& event)
m_selection_end = {};
update();
} else if (event.button() == GMouseButton::Right) {
if (m_ptm_fd == -1)
return;
auto text = GClipboard::the().data();
if (text.is_empty())
return;
@ -582,8 +603,10 @@ void TerminalWidget::terminal_did_resize(u16 columns, u16 rows)
winsize ws;
ws.ws_row = rows;
ws.ws_col = columns;
int rc = ioctl(m_ptm_fd, TIOCSWINSZ, &ws);
ASSERT(rc == 0);
if (m_ptm_fd != -1) {
int rc = ioctl(m_ptm_fd, TIOCSWINSZ, &ws);
ASSERT(rc == 0);
}
}
void TerminalWidget::beep()

View file

@ -18,6 +18,8 @@ public:
TerminalWidget(int ptm_fd, bool automatic_size_policy, RefPtr<CConfigFile> config);
virtual ~TerminalWidget() override;
void set_pty_master_fd(int fd);
void create_window();
void flush_dirty_lines();
@ -44,6 +46,7 @@ public:
virtual bool accepts_focus() const override { return true; }
Function<void(const StringView&)> on_title_change;
Function<void()> on_command_exit;
private:
// ^GWidget