add a poll based EventManager and use it for ncurse client update

This commit is contained in:
Maxime Coste 2012-08-28 22:32:15 +02:00
parent d5dc5dff7f
commit ab47b72dc8
3 changed files with 105 additions and 24 deletions

45
src/event_manager.cc Normal file
View File

@ -0,0 +1,45 @@
#include "event_manager.hh"
#include <algorithm>
namespace Kakoune
{
void EventManager::watch(int fd, EventHandler handler)
{
auto event = std::find_if(m_events.begin(), m_events.end(),
[&](const pollfd& pfd) { return pfd.fd == fd; });
if (event != m_events.end())
throw runtime_error("fd already watched");
m_events.push_back(pollfd{ fd, POLLIN | POLLPRI, 0 });
m_handlers.push_back(std::move(handler));
}
void EventManager::unwatch(int fd)
{
for (size_t i = 0; i < m_events.size(); ++i)
{
if (m_events[i].fd == fd)
{
m_events.erase(m_events.begin() + i);
m_handlers.erase(m_handlers.begin() + i);
return;
}
}
}
void EventManager::handle_next_events()
{
int res = poll(m_events.data(), m_events.size(), -1);
if (res > 0)
{
for (size_t i = 0; i < m_events.size(); ++i)
{
if (m_events[i].revents & POLLIN)
m_handlers[i](m_events[i].fd);
}
}
}
}

29
src/event_manager.hh Normal file
View File

@ -0,0 +1,29 @@
#ifndef event_manager_hh_INCLUDED
#define event_manager_hh_INCLUDED
#include <poll.h>
#include "utils.hh"
namespace Kakoune
{
using EventHandler = std::function<void (int fd)>;
class EventManager : public Singleton<EventManager>
{
public:
void watch(int fd, EventHandler handler);
void unwatch(int fd);
void handle_next_events();
private:
std::vector<pollfd> m_events;
std::vector<EventHandler> m_handlers;
};
}
#endif // event_manager_hh_INCLUDED

View File

@ -14,6 +14,7 @@
#include "filter_registry.hh"
#include "hook_manager.hh"
#include "option_manager.hh"
#include "event_manager.hh"
#include "context.hh"
#include "ncurses.hh"
#include "regex.hh"
@ -442,6 +443,32 @@ std::unordered_map<Key, std::function<void (Context& context)>> keymap =
void run_unit_tests();
void manage_next_keypress(Context& context)
{
static int count = 0;
try
{
Key key = context.client().get_key();
if (key.modifiers == Key::Modifiers::None and isdigit(key.key))
count = count * 10 + key.key - '0';
else
{
auto it = keymap.find(key);
if (it != keymap.end())
{
context.numeric_param(count);
it->second(context);
context.draw_ifn();
}
count = 0;
}
}
catch (Kakoune::runtime_error& error)
{
context.print_status(error.description());
}
}
int main(int argc, char* argv[])
{
GlobalOptionManager option_manager;
@ -452,6 +479,7 @@ int main(int argc, char* argv[])
RegisterManager register_manager;
HighlighterRegistry highlighter_registry;
FilterRegistry filter_registry;
EventManager event_manager;
run_unit_tests();
@ -507,32 +535,11 @@ int main(int argc, char* argv[])
context.change_editor(*buffer->get_or_create_window());
}
event_manager.watch(0, [&](int) { manage_next_keypress(context); });
context.draw_ifn();
int count = 0;
while(not quit_requested)
{
try
{
Key key = context.client().get_key();
if (key.modifiers == Key::Modifiers::None and isdigit(key.key))
count = count * 10 + key.key - '0';
else
{
auto it = keymap.find(key);
if (it != keymap.end())
{
context.numeric_param(count);
it->second(context);
context.draw_ifn();
}
count = 0;
}
}
catch (Kakoune::runtime_error& error)
{
context.print_status(error.description());
}
}
event_manager.handle_next_events();
}
catch (Kakoune::exception& error)
{