Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ftxui::ScreenInteractive disables raw mode some time after program ends #994

Open
temik-kemper opened this issue Jan 23, 2025 · 2 comments

Comments

@temik-kemper
Copy link

temik-kemper commented Jan 23, 2025

it seems like ftxui::ScreenInteractive disables raw mode only after the program exited, so if mouse was moving on terminal screen i get a few garbage symbols in terminal
same if program stops by SIGINT or by ScreenInteractive.Exit()

minimal working example

#include "ftxui/component/component.hpp"
#include "ftxui/component/screen_interactive.hpp"

int main(){
    auto screen = ftxui::ScreenInteractive::Fullscreen();
    auto testComponent = ftxui::Renderer([](){return ftxui::text("test Component");});
    screen.Loop(testComponent);
    return 0;
}

output(sometimes) :

# ./issue 
# 1;48;10M

program is run on arm processor on embedded linux, to which I'm connecting by ssh using "GNOME Terminal" version 3.44.0 on linux mint
ftxui::ScreenInteractive.TrackMouse(false) doesn't fix it
the only consistent workaround i found is this monstrosity

#include "ftxui/component/component.hpp"
#include "ftxui/component/screen_interactive.hpp"

#include <stdlib.h>
#include <termios.h>
#include <unistd.h>
struct termios orig_termios;

int main(){
    tcgetattr(STDIN_FILENO, &orig_termios);
    { // so screen destructor is called first
        auto screen = ftxui::ScreenInteractive::Fullscreen();
        screen.TrackMouse(false);
        auto testComponent = ftxui::Renderer([](){return ftxui::text("test Component");});
        screen.Loop(testComponent);
    }
    tcsetattr(STDIN_FILENO, TCSAFLUSH, &orig_termios);
    // std::system("clear");
    return 0;
}
@temik-kemper
Copy link
Author

this problem is present on every linux terminal i tried, only xterm didn't put garbage escape symbols in console
still not sure how on_exit_functions operates, but my guess is that there is a problem near

on_exit_functions.emplace(
      [=] { tcsetattr(STDIN_FILENO, TCSANOW, &terminal); });

from documentation
tcsetattr
tcgetattr

  • If optional_actions is TCSANOW, the change shall occur immediately.
  • If optional_actions is TCSADRAIN, the change shall occur after all output written to fildes is transmitted. This function should be used when changing parameters that affect output.
  • If optional_actions is TCSAFLUSH, the change shall occur after all output written to fildes is transmitted, and all input so far received but not read shall be discarded before the change is made.

Applications that need all of the requested changes made to work properly should follow tcsetattr() with a call to tcgetattr() and compare the appropriate field values.

Unfortunately, i was not able to fix garbage escape sequence in console even trying these fixes.
I tried flushing stdin and stdout with tcflush, but it did nothing.
why does ScreenInteractive have no destructor ? i understand that there is strange mechanism with destructor of loop, but i still don't quite understand why such pattern is used.

@ArthurSonzogni
Copy link
Owner

Thanks for reporting this!

I guess some data has accumulated in the buffer in between the last time it was processed and when we disabled raw mode.

I suspect we should clear stdin after disabling raw mode. It means adding yet another:

on_exit_functions.emplace(<code to clear stdin>)

before restoring the terminal configuration:

  on_exit_functions.emplace(
      [=] { tcsetattr(STDIN_FILENO, TCSANOW, &terminal); });

Could you please try whether this would work?

why does ScreenInteractive have no destructor ? i understand that there is strange mechanism with destructor of loop, but i still don't quite understand why such pattern is used.

They happen in Install() and Uninstall, which are themselves called from PreMain() and PostMain() from the Loop()

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants