From dd76f9087fe93db5ced608ee3c744f299b933cbe Mon Sep 17 00:00:00 2001 From: Michael Vetter Date: Sat, 11 Apr 2026 23:45:36 +0200 Subject: [PATCH] fix: resolve issues with async editor If we build Profanity without GTK we dont iterate the context so we will never know when the editor exited. Calling `g_main_context_iteration()` or finally switching to GMainLoop fixes this. So far calling `tray_update()` does this for us in GTK builds. So this went unnoticed. The editor will inherit ignored signal handlers (SIGINT, SIGTSTP, SIGPIPE) from us. Neovim uses libuv which seems to check SIGINT on startup to determine whether the environment is interactive or not. We now reset these signals to SIG_DFL in the child process before execvp. Profanity uses readline which still competed for terminal input with the editor. We only took care about other Profanity UI processes in our previous commit. This led to misordered characters in the editor. In my tests with vim everything worked fine and these bugs were discovered when a user used neovim. Fixes: https://github.com/profanity-im/profanity/issues/2148 Ref: 36ec2b0ae1fa7afcdfe6f166323955b8bd121b0f Signed-off-by: Michael Vetter --- src/profanity.c | 2 ++ src/tools/editor.c | 7 +++++++ src/ui/core.c | 2 ++ src/ui/inputwin.c | 19 ++++++++++++++++++- src/ui/inputwin.h | 2 ++ 5 files changed, 31 insertions(+), 1 deletion(-) diff --git a/src/profanity.c b/src/profanity.c index ec6d30678..dc80c9b08 100644 --- a/src/profanity.c +++ b/src/profanity.c @@ -139,6 +139,8 @@ prof_run(gchar* log_level, gchar* account_name, gchar* config_file, gchar* log_f session_process_events(); iq_autoping_check(); ui_update(); + while (g_main_context_iteration(NULL, FALSE)) + ; #ifdef HAVE_GTK tray_update(); #endif diff --git a/src/tools/editor.c b/src/tools/editor.c index f762e7584..e05137628 100644 --- a/src/tools/editor.c +++ b/src/tools/editor.c @@ -14,6 +14,7 @@ #include #include #include +#include #include "config/files.h" #include "config/preferences.h" @@ -128,6 +129,12 @@ launch_editor(gchar* initial_content, void (*callback)(gchar* content, void* dat return TRUE; } else if (pid == 0) { // Child process: Inherits TTY from parent + + // Reset signal handlers that profanity sets so the editor doesn't inherit them + signal(SIGINT, SIG_DFL); + signal(SIGTSTP, SIG_DFL); + signal(SIGPIPE, SIG_DFL); + if (editor_argv && editor_argv[0]) { execvp(editor_argv[0], editor_argv); } diff --git a/src/ui/core.c b/src/ui/core.c index 4e8a76068..5902f86a3 100644 --- a/src/ui/core.c +++ b/src/ui/core.c @@ -179,6 +179,7 @@ ui_reset_idle_time(void) void ui_suspend(void) { + inp_suspend(); endwin(); } @@ -186,6 +187,7 @@ void ui_resume(void) { refresh(); + inp_resume(); } void diff --git a/src/ui/inputwin.c b/src/ui/inputwin.c index f53b7889b..173caf546 100644 --- a/src/ui/inputwin.c +++ b/src/ui/inputwin.c @@ -65,6 +65,7 @@ static fd_set fds; static int r; static char* inp_line = NULL; static gboolean get_password = FALSE; +static gboolean is_suspended = FALSE; static void _inp_win_update_virtual(void); static int _inp_edited(const wint_t ch); @@ -172,7 +173,7 @@ char* inp_readline(void) { // UI is suspended - if (isendwin()) { + if (is_suspended || isendwin()) { g_usleep(100000); // 100ms return NULL; } @@ -272,6 +273,22 @@ inp_close(void) discard = NULL; } +void +inp_suspend(void) +{ + is_suspended = TRUE; + rl_callback_handler_remove(); + rl_deprep_terminal(); +} + +void +inp_resume(void) +{ + is_suspended = FALSE; + rl_callback_handler_install(NULL, _inp_rl_linehandler); + rl_prep_terminal(0); +} + char* inp_get_line(void) { diff --git a/src/ui/inputwin.h b/src/ui/inputwin.h index 88fbec4f8..5a7c069c0 100644 --- a/src/ui/inputwin.h +++ b/src/ui/inputwin.h @@ -18,6 +18,8 @@ void create_input_window(void); void inp_close(void); void inp_win_resize(void); void inp_put_back(void); +void inp_suspend(void); +void inp_resume(void); char* inp_get_password(void); char* inp_get_line(void);