I thought that it would be nice to trigger CK_EditNew and other actions
when running a macro, or a usermenu entry. It can be done via signals
(USR1), attached is a patch.

For running from macros inside mc/mcedit, what's sufficient is to execute:
mc --ck EditNew (because the pid is exported). For outside, one has to
specify the pid via: MC_PID=1234 mc --ck EditNew.

It works for mc and mcedit. What do you think?

PS. A little video: asciinema.org/a/432747

-- 
Best regards,
Sebastian Gniazdowski
From 3c00732b6aa0818bd9589e6addaba09c35ac0186 Mon Sep 17 00:00:00 2001
From: Sebastian Gniazdowski <sgniazdow...@gmail.com>
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) <YEARS>
+   Free Software Foundation, Inc.
+
+   Written by:
+   AUTHOR <MAIL>, 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 <http://www.gnu.org/licenses/>.
+ */
+
+/** \file
+ *  \brief This is a template file (here goes brief description).
+ *  \author Author1
+ *  \author Author2
+ *  \date 20xx
+ *
+ *  Detailed description.
+ */
+
+#include <config.h>
+
+#include <signal.h>
+
+#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

_______________________________________________
mc-devel mailing list
https://mail.gnome.org/mailman/listinfo/mc-devel

Reply via email to