From 299e22ca7c3a976c7f2edf99f4ff248f6e4c9f85 Mon Sep 17 00:00:00 2001 From: Maxime Coste Date: Sun, 21 Jan 2018 12:00:40 +1100 Subject: [PATCH] Do not block when waiting for next event if we have pending input Handle next event should never block if we have already accumulated input that we want to process. As we can accumulate new input in lots of places (everytime we run a shell process for example, we might end up reading input keys. That can be triggered during the mode line generation which takes place during display of the window) Fixes #1804 --- src/client.hh | 1 + src/client_manager.cc | 5 +++++ src/client_manager.hh | 1 + src/event_manager.cc | 6 +++--- src/event_manager.hh | 2 +- src/main.cc | 3 ++- 6 files changed, 13 insertions(+), 5 deletions(-) diff --git a/src/client.hh b/src/client.hh index b12bd854..d7db0391 100644 --- a/src/client.hh +++ b/src/client.hh @@ -38,6 +38,7 @@ public: Client(Client&&) = delete; bool process_pending_inputs(); + bool has_pending_inputs() const { return not m_pending_keys.empty(); } void menu_show(Vector choices, BufferCoord anchor, MenuStyle style); void menu_select(int selected); diff --git a/src/client_manager.cc b/src/client_manager.cc index c721f1db..9cb5f8e5 100644 --- a/src/client_manager.cc +++ b/src/client_manager.cc @@ -90,6 +90,11 @@ void ClientManager::process_pending_inputs() const } } +bool ClientManager::has_pending_inputs() const +{ + return contains_that(m_clients, [](auto&& c) { return c->has_pending_inputs(); }); +} + void ClientManager::remove_client(Client& client, bool graceful, int status) { auto it = find(m_clients, &client); diff --git a/src/client_manager.hh b/src/client_manager.hh index 5508b519..f6fb30e3 100644 --- a/src/client_manager.hh +++ b/src/client_manager.hh @@ -36,6 +36,7 @@ public: void redraw_clients() const; void process_pending_inputs() const; + bool has_pending_inputs() const; Client* get_client_ifp(StringView name); Client& get_client(StringView name); diff --git a/src/event_manager.cc b/src/event_manager.cc index 63f47858..cb69fc5e 100644 --- a/src/event_manager.cc +++ b/src/event_manager.cc @@ -69,7 +69,7 @@ EventManager::~EventManager() kak_assert(m_timers.empty()); } -void EventManager::handle_next_events(EventMode mode, sigset_t* sigmask) +void EventManager::handle_next_events(EventMode mode, sigset_t* sigmask, bool block) { int max_fd = 0; fd_set rfds, wfds, efds; @@ -92,7 +92,7 @@ void EventManager::handle_next_events(EventMode mode, sigset_t* sigmask) bool with_timeout = false; timespec ts{}; - if (not m_timers.empty()) + if (block and not m_timers.empty()) { auto next_date = (*std::min_element( m_timers.begin(), m_timers.end(), [](Timer* lhs, Timer* rhs) { @@ -109,7 +109,7 @@ void EventManager::handle_next_events(EventMode mode, sigset_t* sigmask) } } int res = pselect(max_fd + 1, &rfds, &wfds, &efds, - with_timeout ? &ts : nullptr, sigmask); + not block or with_timeout ? &ts : nullptr, sigmask); // copy forced fds *after* select, so that signal handlers can write to // m_forced_fd, interupt select, and directly be serviced. diff --git a/src/event_manager.hh b/src/event_manager.hh index 5d8c1ca5..857cb863 100644 --- a/src/event_manager.hh +++ b/src/event_manager.hh @@ -86,7 +86,7 @@ public: EventManager(); ~EventManager(); - void handle_next_events(EventMode mode, sigset_t* sigmask = nullptr); + void handle_next_events(EventMode mode, sigset_t* sigmask = nullptr, bool block = true); // force the watchers associated with fd to be executed // on next handle_next_events call. diff --git a/src/main.cc b/src/main.cc index ad5646f8..e98a09b4 100644 --- a/src/main.cc +++ b/src/main.cc @@ -683,7 +683,8 @@ int run_server(StringView session, StringView server_init, (flags & ServerFlags::Daemon))) { client_manager.redraw_clients(); - event_manager.handle_next_events(EventMode::Normal); + event_manager.handle_next_events(EventMode::Normal, nullptr, + not client_manager.has_pending_inputs()); client_manager.process_pending_inputs(); client_manager.clear_client_trash(); client_manager.clear_window_trash();