diff --git a/src/tools/editor.c b/src/tools/editor.c index a8648307..dc3bdeb8 100644 --- a/src/tools/editor.c +++ b/src/tools/editor.c @@ -32,9 +32,20 @@ typedef struct EditorContext void* user_data; } EditorContext; +// Set TRUE for the lifetime of an editor session (from launch_editor up to +// _editor_exit_cb / fork-error cleanup). The async editor model lost the old +// editor_task.active check from the pthread implementation; without this +// guard a second launch_editor (e.g. via a plugin dispatched through +// g_main_context_iteration) would call ui_suspend again and fork a second +// editor that fights the first one for the terminal, then prematurely +// ui_resume when either exits. +static gboolean editor_active = FALSE; + static void _editor_exit_cb(GPid pid, gint status, gpointer data) { + editor_active = FALSE; + EditorContext* ctx = data; gchar* contents = NULL; GError* error = NULL; @@ -70,6 +81,11 @@ _editor_exit_cb(GPid pid, gint status, gpointer data) gboolean launch_editor(gchar* initial_content, void (*callback)(gchar* content, void* data), void* user_data) { + if (editor_active) { + cons_show_error("An editor session is already active."); + return TRUE; + } + auto_gchar gchar* filename = NULL; auto_gerror GError* glib_error = NULL; const char* jid = connection_get_barejid(); @@ -118,6 +134,7 @@ launch_editor(gchar* initial_content, void (*callback)(gchar* content, void* dat ctx->callback = callback; ctx->user_data = user_data; + editor_active = TRUE; ui_suspend(); // Force GLib to install its SIGCHLD handler before forking. Creating a @@ -129,6 +146,7 @@ launch_editor(gchar* initial_content, void (*callback)(gchar* content, void* dat pid_t pid = fork(); if (pid == -1) { log_error("[Editor] Failed to fork: %s", strerror(errno)); + editor_active = FALSE; ui_resume(); ui_resize(); cons_show_error("Failed to start editor: %s", strerror(errno));