From 3c00732b6aa0818bd9589e6addaba09c35ac0186 Mon Sep 17 00:00:00 2001 From: Sebastian Gniazdowski Date: Sun, 29 Aug 2021 08:58:37 +0200 Subject: Ability to trigger actions (eg. EditNew) from outside of mc/mcedit, via signals. --- src/Makefile.am | 1 + src/args.c | 9 ++ src/args.h | 1 + src/filemanager/panel.c | 4 + src/filemanager/panel.h | 1 + src/main.c | 19 ++- src/signal_ck_action.c | 153 ++++++++++++++++++ .../template.h => src/signal_ck_action.h | 9 +- 8 files changed, 192 insertions(+), 5 deletions(-) create mode 100644 src/signal_ck_action.c copy maint/templates/template.h => src/signal_ck_action.h (73%) diff --git a/src/Makefile.am b/src/Makefile.am index 2739ea3d2..8ce25aeea 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -68,6 +68,7 @@ mc_SOURCES = \ libinternal_la_SOURCES = \ $(SRC_mc_conssaver) \ + signal_ck_action.c signal_ck_action.h \ args.c args.h \ clipboard.c clipboard.h \ events_init.c events_init.h \ diff --git a/src/args.c b/src/args.c index 5b4b106eb..a6fd935f4 100644 --- a/src/args.c +++ b/src/args.c @@ -85,6 +85,9 @@ char *mc_run_param1 = NULL; /* If true, show version info and exit */ static gboolean mc_args__show_version = FALSE; +/* Name of the action to run on an outer mc session */ +char *mc_args__ck_action; + /* forward declarations */ static gboolean parse_mc_e_argument (const gchar * option_name, const gchar * value, gpointer data, GError ** mcerror); @@ -114,6 +117,12 @@ static const GOptionEntry argument_main_table[] = { NULL }, + { + "ck", 'o', G_OPTION_FLAG_IN_MAIN, G_OPTION_ARG_STRING, + &mc_args__ck_action, + N_("Runs the given action on an outer mc session (to be used in scripts run from mc)"), + NULL + }, /* options for wrappers */ { "datadir", 'f', G_OPTION_FLAG_IN_MAIN, G_OPTION_ARG_NONE, diff --git a/src/args.h b/src/args.h index 69b25ec16..75fa68053 100644 --- a/src/args.h +++ b/src/args.h @@ -18,6 +18,7 @@ typedef struct /*** global variables defined in .c file *********************************************************/ +extern char *mc_args__ck_action; extern gboolean mc_args__force_xterm; extern gboolean mc_args__nomouse; extern gboolean mc_args__force_colors; diff --git a/src/filemanager/panel.c b/src/filemanager/panel.c index e8f4032ca..13190d1d2 100644 --- a/src/filemanager/panel.c +++ b/src/filemanager/panel.c @@ -4217,6 +4217,10 @@ panel_dir_list_callback (dir_list_cb_state_t state, void *data) /* --------------------------------------------------------------------------------------------- */ /*** public functions ****************************************************************************/ /* --------------------------------------------------------------------------------------------- */ +gboolean panel_widget_is_panel(const Widget *w) +{ + return (w != NULL && w->callback == panel_callback); +} void try_to_select (WPanel * panel, const char *name) diff --git a/src/filemanager/panel.h b/src/filemanager/panel.h index 05c8aa56d..c6ebc6a66 100644 --- a/src/filemanager/panel.h +++ b/src/filemanager/panel.h @@ -161,6 +161,7 @@ extern mc_fhl_t *mc_filehighlight; /*** declarations of public functions ************************************************************/ +gboolean panel_widget_is_panel(const Widget *w); WPanel *panel_sized_empty_new (const char *panel_name, int y, int x, int lines, int cols); WPanel *panel_sized_with_dir_new (const char *panel_name, int y, int x, int lines, int cols, const vfs_path_t * vpath); diff --git a/src/main.c b/src/main.c index 2c25cc019..904399ebf 100644 --- a/src/main.c +++ b/src/main.c @@ -57,6 +57,8 @@ #include "lib/vfs/vfs.h" /* vfs_init(), vfs_shut() */ #include "lib/logging.h" +#include "signal_ck_action.h" + #include "filemanager/filemanager.h" #include "filemanager/treestore.h" /* tree_store_save */ #include "filemanager/layout.h" @@ -308,7 +310,7 @@ main (int argc, char *argv[]) char *env_loglevel_str; mc_global.run_from_parent_mc = !check_sid (); - + cksig_init_signal(); /* We had LC_CTYPE before, LC_ALL includs LC_TYPE as well */ #ifdef HAVE_SETLOCALE (void) setlocale (LC_ALL, ""); @@ -334,7 +336,7 @@ main (int argc, char *argv[]) if (!mc_args_parse (&argc, &argv, "mc", &mcerror)) { startup_exit_falure: - fprintf (stderr, _("Failed to run:\n%s\n"), mcerror->message); + fprintf (stderr, _("Failed to run:\n%s\n"), mcerror?mcerror->message:"no error"); g_error_free (mcerror); startup_exit_ok: mc_shell_deinit (); @@ -342,6 +344,19 @@ main (int argc, char *argv[]) return exit_code; } + /* Run in CK-signal only mode? */ + if (mc_args__ck_action != NULL) + { + cksig_signal_action(mc_args__ck_action); + goto startup_exit_ok; + } + + /* Export pid in MC_PID variable for the CK-signaling */ + { + char *val = g_strdup_printf("%li",(long)getpid()); + g_setenv("MC_PID", val, TRUE); + } + /* do this before mc_args_show_info () to view paths in the --datadir-info output */ OS_Setup (); diff --git a/src/signal_ck_action.c b/src/signal_ck_action.c new file mode 100644 index 000000000..460074803 --- /dev/null +++ b/src/signal_ck_action.c @@ -0,0 +1,153 @@ +/* + Implements ability to trigger actions (like CK_EditFile) from outside of + mc process, via USR1 signal. + + Copyright (C) + Free Software Foundation, Inc. + + Written by: + AUTHOR , YEARS. + + This file is part of the Midnight Commander. + + The Midnight Commander is free software: you can redistribute it + and/or modify it under the terms of the GNU General Public License as + published by the Free Software Foundation, either version 3 of the License, + or (at your option) any later version. + + The Midnight Commander is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + */ + +/** \file + * \brief This is a template file (here goes brief description). + * \author Author1 + * \author Author2 + * \date 20xx + * + * Detailed description. + */ + +#include + +#include + +#include "lib/global.h" +#include "lib/keybind.h" +#include "lib/logging.h" +//#include "lib/wid +#include "src/filemanager/filemanager.h" +#include "src/filemanager/panel.h" +#include "src/editor/editwidget.h" +#include "src/signal_ck_action.h" + +/*** global variables ****************************************************************************/ + +/*** file scope macro definitions ****************************************************************/ + +/*** file scope type declarations ****************************************************************/ + +/*** file scope variables ************************************************************************/ +static struct sigaction usr1; + +/*** file scope functions ************************************************************************/ +/* --------------------------------------------------------------------------------------------- */ + +static void handler (int sig G_GNUC_UNUSED, siginfo_t *siginfo, void *context G_GNUC_UNUSED) +{ + int ck_id = (long)siginfo->si_value.sival_int; + + cksig_exec_com(ck_id, 0, NULL); +} + +/* --------------------------------------------------------------------------------------------- */ +/*** public functions ****************************************************************************/ +/* --------------------------------------------------------------------------------------------- */ +gboolean cksig_signal_action(const char *action_name) +{ + union sigval sig_parm = {0}; + long ck_id, pid; + const char *str_pid = g_getenv("MC_PID"); + + g_return_val_if_fail (action_name != NULL, FALSE); + + ck_id = keybind_lookup_operation(action_name); + g_return_val_if_fail (ck_id > 0, FALSE); + + if (str_pid == NULL || *str_pid=='\0') + { + printf("Run me from within an MC/MCEdit instance, e.g.: from a macro or" + "a user-menu. The --ck option will run the action in that instance."); + g_return_val_if_fail (str_pid != NULL && *str_pid!='\0', FALSE); + } + pid = g_ascii_strtoull (str_pid, NULL, 10); + if (pid == 0) + { + printf("Error: incorrect pid stored in MC_PID variable (%s)", str_pid); + g_return_val_if_fail (pid != 0, FALSE); + } + + sig_parm.sival_int = ck_id; + if (sigqueue(pid, SIGUSR1, sig_parm)!=0) + { + printf("Problem sending signal: %s", g_strerror(errno)); + return FALSE; + } + return TRUE; +} + +gboolean cksig_exec_com(long ck_id, PARM_DATA) +{ + cb_ret_t cb_ret = MSG_NOT_HANDLED, idx=0; + void **ptr, *widgets[8] = {0}; + + /* No valid CK operation passed in? Look for in parm. */ + if (ck_id <= 0 && parm > 0) + { + ck_id = parm; + parm = 0; + } + + /* If CK ID not found, then exit with false. */ + g_return_val_if_fail(ck_id>0, FALSE); + + /* Append all other top dialogs */ + for (GList *top = top_dlg; top != NULL && idx<7; top=top->next) + { + WGroup *g = GROUP(top->data); + Widget *picked; + if (g != NULL && g->current != NULL) + { + picked = WIDGET (g->current->data); + if (edit_widget_is_editor (picked) || panel_widget_is_panel (picked)) + /* Send also to eg. window of currently edited file */ + widgets[idx++]=picked; + } + widgets[idx++]=top->data; + } + + /* Execute on various widgets looking for MSG_HANDLED response */ + for (ptr = widgets; ptr != NULL && *ptr != NULL; ptr ++) + { + cb_ret = send_message(*ptr, 0, MSG_ACTION, ck_id, NULL); + if (cb_ret == MSG_HANDLED) + break; + } + return cb_ret == MSG_HANDLED; +} +gboolean cksig_init_signal(void) +{ + usr1.sa_sigaction = &handler; + usr1.sa_flags = SA_SIGINFO; + if (sigaction(SIGUSR1, &usr1, NULL) < 0) { + return FALSE; + } + + /* Handler successfully installed. */ + return TRUE; +} diff --git a/maint/templates/template.h b/src/signal_ck_action.h similarity index 73% copy from maint/templates/template.h copy to src/signal_ck_action.h index 97aaa55d5..f15333e2d 100644 --- a/maint/templates/template.h +++ b/src/signal_ck_action.h @@ -1,5 +1,5 @@ -#ifndef MC__TEMPLATE_H -#define MC__TEMPLATE_H +#ifndef MC__CK_SIGNALS_H +#define MC__CK_SIGNALS_H /*** typedefs(not structures) and defined constants **********************************************/ @@ -10,7 +10,10 @@ /*** global variables defined in .c file *********************************************************/ /*** declarations of public functions ************************************************************/ +gboolean cksig_signal_action(const char *action_name); +gboolean cksig_exec_com(long com, PARM_DATA); +gboolean cksig_init_signal(void); /*** inline functions ****************************************************************************/ -#endif /* MC__TEMPLATE_H */ +#endif /* MC__CK_SIGNALS_H */ -- 2.28.0