Rework the way UI can trigger a client quitting

Add a UserInterface::is_ok method and return false on
SIGHUP/stdin closing/socket dropping

This should be cleaner and more robust than the previous SIGHUP
handling code.

Fixes #1594
This commit is contained in:
Maxime Coste 2018-04-29 22:27:28 +10:00
parent 57112b0845
commit 178d2d3cd3
10 changed files with 40 additions and 39 deletions

View File

@ -71,6 +71,11 @@ Client::~Client()
context().selections());
}
bool Client::is_ui_ok() const
{
return m_ui->is_ok();
}
bool Client::process_pending_inputs()
{
const bool debug_keys = (bool)(context().options()["debug"].get<DebugFlags>() & DebugFlags::Keys);

View File

@ -37,6 +37,8 @@ public:
Client(Client&&) = delete;
bool is_ui_ok() const;
bool process_pending_inputs();
bool has_pending_inputs() const { return not m_pending_keys.empty(); }

View File

@ -411,7 +411,10 @@ void JsonUI::parse_requests(EventMode mode)
{
ssize_t size = ::read(0, buf, bufsize);
if (size == -1 or size == 0)
{
m_stdin_watcher.close_fd();
break;
}
m_requests += StringView{buf, buf + size};
}

View File

@ -19,6 +19,8 @@ public:
JsonUI(const JsonUI&) = delete;
JsonUI& operator=(const JsonUI&) = delete;
bool is_ok() const override { return m_stdin_watcher.fd() != -1; }
void draw(const DisplayBuffer& display_buffer,
const Face& default_face,
const Face& buffer_padding) override;

View File

@ -378,7 +378,6 @@ void register_options()
static Client* local_client = nullptr;
static int local_client_exit = 0;
static sig_atomic_t sighup_raised = 0;
static UserInterface* local_ui = nullptr;
static bool convert_to_client_pending = false;
@ -403,6 +402,7 @@ std::unique_ptr<UserInterface> make_ui(UIType ui_type)
struct DummyUI : UserInterface
{
DummyUI() { set_signal_handler(SIGINT, SIG_DFL); }
bool is_ok() const override { return true; }
void menu_show(ConstArrayView<DisplayLine>, DisplayCoord,
Face, Face, MenuStyle) override {}
void menu_select(int) override {}
@ -453,10 +453,6 @@ std::unique_ptr<UserInterface> create_local_ui(UIType ui_type)
{
kak_assert(not local_ui);
local_ui = this;
m_old_sighup = set_signal_handler(SIGHUP, [](int) {
static_cast<LocalUI*>(local_ui)->on_sighup();
sighup_raised = 1;
});
m_old_sigtstp = set_signal_handler(SIGTSTP, [](int) {
if (ClientManager::instance().count() == 1 and
@ -482,7 +478,6 @@ std::unique_ptr<UserInterface> create_local_ui(UIType ui_type)
~LocalUI() override
{
set_signal_handler(SIGHUP, m_old_sighup);
set_signal_handler(SIGTSTP, m_old_sigtstp);
local_client = nullptr;
local_ui = nullptr;
@ -499,7 +494,6 @@ std::unique_ptr<UserInterface> create_local_ui(UIType ui_type)
private:
using SigHandler = void (*)(int);
SigHandler m_old_sighup;
SigHandler m_old_sigtstp;
};
@ -692,12 +686,11 @@ int run_server(StringView session, StringView server_init,
client_manager.clear_window_trash();
buffer_manager.clear_buffer_trash();
if (sighup_raised and local_client)
if (local_client and not local_client->is_ui_ok())
{
ClientManager::instance().remove_client(*local_client, false, 0);
ClientManager::instance().remove_client(*local_client, false, -1);
if (not client_manager.empty() and fork_server_to_background())
return 0;
sighup_raised = 0;
}
else if (convert_to_client_pending)
{

View File

@ -219,10 +219,12 @@ void NCursesUI::set_face(NCursesWin* window, Face face, const Face& default_face
}
static sig_atomic_t resize_pending = 0;
static sig_atomic_t sighup_raised = 0;
void on_term_resize(int)
template<sig_atomic_t* signal_flag>
static void signal_handler(int)
{
resize_pending = 1;
*signal_flag = 1;
EventManager::instance().force_signal(0);
}
@ -271,7 +273,8 @@ NCursesUI::NCursesUI()
enable_mouse(true);
set_signal_handler(SIGWINCH, on_term_resize);
set_signal_handler(SIGWINCH, &signal_handler<&resize_pending>);
set_signal_handler(SIGHUP, &signal_handler<&sighup_raised>);
check_resize(true);
@ -516,18 +519,15 @@ void NCursesUI::check_resize(bool force)
werase(curscr);
}
void NCursesUI::on_sighup()
{
set_signal_handler(SIGWINCH, SIG_DFL);
set_signal_handler(SIGCONT, SIG_DFL);
m_window = nullptr;
}
Optional<Key> NCursesUI::get_next_key()
{
if (not m_window)
if (sighup_raised)
{
set_signal_handler(SIGWINCH, SIG_DFL);
set_signal_handler(SIGCONT, SIG_DFL);
m_window = nullptr;
return {};
}
check_resize();

View File

@ -24,6 +24,8 @@ public:
NCursesUI(const NCursesUI&) = delete;
NCursesUI& operator=(const NCursesUI&) = delete;
bool is_ok() const override { return m_window != nullptr; }
void draw(const DisplayBuffer& display_buffer,
const Face& default_face,
const Face& padding_face) override;
@ -59,9 +61,6 @@ public:
DisplayCoord size;
};
protected:
void on_sighup();
private:
void check_resize(bool force = false);
void redraw();

View File

@ -1982,7 +1982,7 @@ template<typename Type, Direction direction, SelectMode mode = SelectMode::Repla
void move_cursor(Context& context, NormalParams params)
{
kak_assert(mode == SelectMode::Replace or mode == SelectMode::Extend);
const Type offset(direction * std::max(params.count,1));
const Type offset{direction * std::max(params.count,1)};
const ColumnCount tabstop = context.options()["tabstop"].get<int>();
auto& selections = context.selections();
for (auto& sel : selections)

View File

@ -315,6 +315,7 @@ public:
RemoteUI(int socket, DisplayCoord dimensions);
~RemoteUI() override;
bool is_ok() const override { return m_socket_watcher.fd() != -1; }
void menu_show(ConstArrayView<DisplayLine> choices,
DisplayCoord anchor, Face fg, Face bg,
MenuStyle style) override;
@ -345,9 +346,6 @@ public:
void set_ui_options(const Options& options) override;
void set_client(Client* client) { m_client = client; }
Client* client() const { return m_client.get(); }
void exit(int status);
private:
@ -356,8 +354,6 @@ private:
DisplayCoord m_dimensions;
OnKeyCallback m_on_key;
RemoteBuffer m_send_buffer;
SafePtr<Client> m_client;
};
static bool send_data(int fd, RemoteBuffer& buffer)
@ -390,7 +386,7 @@ RemoteUI::RemoteUI(int socket, DisplayCoord dimensions)
if (m_reader.type() != MessageType::Key)
{
ClientManager::instance().remove_client(*m_client, false, -1);
m_socket_watcher.close_fd();
return;
}
@ -404,7 +400,7 @@ RemoteUI::RemoteUI(int socket, DisplayCoord dimensions)
catch (const disconnected& err)
{
write_to_debug_buffer(format("Error while transfering remote messages: {}", err.what()));
ClientManager::instance().remove_client(*m_client, false, -1);
m_socket_watcher.close_fd();
}
}),
m_dimensions(dimensions)
@ -725,11 +721,10 @@ private:
auto dimensions = m_reader.read<DisplayCoord>();
auto env_vars = m_reader.read_hash_map<String, String, MemoryDomain::EnvVars>();
auto* ui = new RemoteUI{sock, dimensions};
if (auto* client = ClientManager::instance().create_client(
ClientManager::instance().create_client(
std::unique_ptr<UserInterface>(ui), pid, std::move(name),
std::move(env_vars), init_cmds, init_coord,
[ui](int status) { ui->exit(status); }))
ui->set_client(client);
[ui](int status) { ui->exit(status); });
Server::instance().remove_accepter(this);
break;

View File

@ -47,6 +47,8 @@ class UserInterface
public:
virtual ~UserInterface() = default;
virtual bool is_ok() const = 0;
virtual void menu_show(ConstArrayView<DisplayLine> choices,
DisplayCoord anchor, Face fg, Face bg,
MenuStyle style) = 0;