From 508b2ef048d85a4285564809ca57518030dcde60 Mon Sep 17 00:00:00 2001 From: ArthurSonzogni Date: Wed, 25 Mar 2020 01:15:46 +0100 Subject: [PATCH] Improve thread usages. --- CMakeLists.txt | 1 + src/ftxui/component/screen_interactive.cpp | 56 ++++++++++++++-------- 2 files changed, 36 insertions(+), 21 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 9c576987..fc2f5854 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -162,6 +162,7 @@ if (FTXUI_BUILD_TESTS AND GTEST_FOUND AND THREADS_FOUND) target_include_directories(dom_tests PRIVATE ${GTest_INCLUDE_DIRS} ) + set_property(TARGET dom_tests PROPERTY CXX_STANDARD 17) gtest_discover_tests(dom_tests) add_test(dom_tests dom_tests) endif() diff --git a/src/ftxui/component/screen_interactive.cpp b/src/ftxui/component/screen_interactive.cpp index 6887ea28..94d415b0 100644 --- a/src/ftxui/component/screen_interactive.cpp +++ b/src/ftxui/component/screen_interactive.cpp @@ -28,6 +28,21 @@ namespace ftxui { +// Produce a stream of Event from a stream of char. +void CharToEventStream(Receiver receiver, Sender sender) { + char c; + while (receiver->Receive(&c)) + Event::Convert(receiver, sender, c); +} + +// Read char from the terminal. +void UnixEventListener(std::atomic* quit, Sender sender) { + // TODO(arthursonzogni): Use a timeout so that it doesn't block even if the + // user doesn't generate new chars. + while (!*quit) + sender->Send((char)getchar()); +} + static const char* HIDE_CURSOR = "\x1B[?25l"; static const char* SHOW_CURSOR = "\x1B[?25h"; @@ -85,7 +100,8 @@ ScreenInteractive ScreenInteractive::FitComponent() { } void ScreenInteractive::PostEvent(Event event) { - event_sender_->Send(event); + if (!quit_) + event_sender_->Send(event); } void ScreenInteractive::Loop(Component* component) { @@ -140,26 +156,20 @@ void ScreenInteractive::Loop(Component* component) { std::cout << std::endl; }); + // Produce a stream of Event from a stream of char. auto char_receiver = MakeReceiver(); - - // Spawn a thread to produce char. auto char_sender = char_receiver->MakeSender(); - std::thread read_char([&] { - // TODO(arthursonzogni): Use a timeout so that it doesn't block even if the - // user doesn't generate new chars. - while (!quit_) - char_sender->Send((char)getchar()); - char_sender.reset(); - }); - - // Spawn a thread producing events and consumer chars. auto event_sender = event_receiver_->MakeSender(); - std::thread convert_char_to_event([&] { - char c; - while (char_receiver->Receive(&c)) - Event::Convert(char_receiver, event_sender, c); - event_sender.reset(); - }); + auto char_to_event_stream = std::thread( + CharToEventStream, std::move(char_receiver), std::move(event_sender)); + + // Depending on the OS, start a thread that will produce events and/or chars. +#if defined(WIN32) + // TODO(arthursonzogni) implement here. +#else + auto unix_event_listener = + std::thread(&UnixEventListener, &quit_, std::move(char_sender)); +#endif // The main loop. while (!quit_) { @@ -171,8 +181,9 @@ void ScreenInteractive::Loop(Component* component) { if (event_receiver_->Receive(&event)) component->OnEvent(event); } - read_char.join(); - convert_char_to_event.join(); + + char_to_event_stream.join(); + unix_event_listener.join(); OnExit(0); } @@ -231,7 +242,10 @@ void ScreenInteractive::Draw(Component* component) { } std::function ScreenInteractive::ExitLoopClosure() { - return [this]() { quit_ = true; }; + return [this]() { + quit_ = true; + event_sender_.reset(); + }; } } // namespace ftxui.