From 644570d3c2930be120f9d1f4baf433d3e4ebbb8d Mon Sep 17 00:00:00 2001 From: ZjYwMj <27451609+ZjYwMj@users.noreply.github.com> Date: Sat, 24 Jul 2021 16:50:12 +0000 Subject: [PATCH 1/3] [1/3] Update lxterminal.h: new, run multiple commands from the command line Adds a new --commands= command line option. Note the s in commands. With the new command line option of --commands=, one can run multiple commands when starting lxterminal from the command line. Each command is automatically paired with a tab. After exhausting existing tabs, new tabs will be automatically created. This feature does not lift the basic limitation of commands in lxterminal command line. Which is, that short lived processes makes the tab they ran within, or the whole window in case of only short lived processes, to get closed as soon as the short lived processes has terminated. This limitation is shortly described in the modified man page. This patch constitutes of modifying 3 files: 1. src/lxterminal.h 2. src/lxterminal.c 3. man/lxterminal.xml The modification of lxterminal.xml, beside describing the new --commands= option, also describes, in some length, some pitfalls of lxterminal. --- src/lxterminal.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/lxterminal.h b/src/lxterminal.h index 328c7432..ef4f8007 100644 --- a/src/lxterminal.h +++ b/src/lxterminal.h @@ -70,6 +70,7 @@ typedef struct _term { GtkWidget * scrollbar; /* Scroll bar, child of horizontal box */ GPid pid; /* Process ID of the process that has this as its terminal */ GClosure * closure; /* Accelerator structure */ + gchar * * command; /* Memory allocated by glib */ gchar * matched_url; gboolean open_menu_on_button_release; gulong exit_handler_id; @@ -79,6 +80,7 @@ typedef struct _term { typedef struct _command_arguments { char * executable; /* Value of argv[0]; points into argument vector */ gchar * * command; /* Value of -e, --command; memory allocated by glib */ + char * commands; /* Value of --commands; points into argument vector */ int geometry_bitmask; unsigned int geometry_columns; /* Value of --geometry */ unsigned int geometry_rows; From 1c510478c4e60215105b70f6c6adf284e2621f34 Mon Sep 17 00:00:00 2001 From: ZjYwMj <27451609+ZjYwMj@users.noreply.github.com> Date: Sat, 24 Jul 2021 16:55:19 +0000 Subject: [PATCH 2/3] [2/3] Update lxterminal.c: new, run multiple commands from the command line Adds a new --commands= command line option. Note the s in commands. With the new command line option of --commands=, one can run multiple commands when starting lxterminal from the command line. Each command is automatically paired with a tab. After exhausting existing tabs, new tabs will be automatically created. This feature does not lift the basic limitation of commands in lxterminal command line. Which is, that short lived processes makes the tab they ran within, or the whole window in case of only short lived processes, to get closed as soon as the short lived processes has terminated. This limitation is shortly described in the modified man page. This patch constitutes of modifying 3 files: 1. src/lxterminal.h 2. src/lxterminal.c 3. man/lxterminal.xml The modification of lxterminal.xml, beside describing the new --commands= option, also describes, in some length, some pitfalls of lxterminal. --- src/lxterminal.c | 143 ++++++++++++++++++++++++++++++----------------- 1 file changed, 92 insertions(+), 51 deletions(-) diff --git a/src/lxterminal.c b/src/lxterminal.c index 142d6a68..1c2990d0 100644 --- a/src/lxterminal.c +++ b/src/lxterminal.c @@ -97,13 +97,14 @@ static gboolean terminal_vte_button_press_event(VteTerminal * vte, GdkEventButto static void terminal_settings_apply_to_term(LXTerminal * terminal, Term * term); static Term * terminal_new(LXTerminal * terminal, const gchar * label, const gchar * pwd, gchar * * env, gchar * * exec); static void terminal_set_geometry_hints(Term * term, GdkGeometry * geometry); -static void terminal_new_tab(LXTerminal * terminal, const gchar * label); +static void terminal_new_tab(LXTerminal * terminal, const gchar * label, const gchar * cmd); static void terminal_free(Term * term); static void terminal_menubar_initialize(LXTerminal * terminal); static void terminal_menu_accelerator_update(LXTerminal * terminal); static void terminal_settings_apply(LXTerminal * terminal); static void terminal_update_menu_shortcuts(Setting * setting); static void terminal_initialize_menu_shortcuts(Setting * setting); +static void terminal_process_requested_command(gchar * * * const command, const gint cmd_len, const gboolean login_shell); /* Menu accelerator saved when the user disables it. */ static char * saved_menu_accelerator = NULL; @@ -293,7 +294,8 @@ static void terminal_initialize_switch_tab_accelerator(Term * term) { /* Formulate the accelerator name. */ char switch_tab_accel[1 + 3 + 1 + 1 + 1]; /* "n" */ - sprintf(switch_tab_accel, "%d", term->index + 1); + /* Casting to unsigned, and %10, to shut off a compilation warning. */ + sprintf(switch_tab_accel, "%d", (unsigned)(term->index + 1)%10); /* Parse the accelerator name. */ guint key; @@ -373,7 +375,7 @@ static void terminal_new_window_activate_event(GtkAction * action, LXTerminal * * Open a new tab. */ static void terminal_new_tab_activate_event(GtkAction * action, LXTerminal * terminal) { - terminal_new_tab(terminal, NULL); + terminal_new_tab(terminal, NULL, NULL); } static void terminal_set_geometry_hints(Term *term, GdkGeometry *geometry) @@ -410,7 +412,7 @@ static void terminal_save_size(LXTerminal * terminal) terminal->row = vte_terminal_get_row_count(VTE_TERMINAL(term->vte)); } -static void terminal_new_tab(LXTerminal * terminal, const gchar * label) +static void terminal_new_tab(LXTerminal * terminal, const gchar * label, const gchar * cmd) { Term * term; gchar * proc_cwd = terminal_get_current_dir(terminal); @@ -419,21 +421,12 @@ static void terminal_new_tab(LXTerminal * terminal, const gchar * label) * If the working directory was determined above, use it; otherwise default to the working directory of the process. * Create the new terminal. */ - if (terminal->login_shell) - { - /* Create a login shell, this should be cleaner. */ - gchar * * exec = g_malloc(3 * sizeof(gchar *)); - exec[0] = g_strdup(terminal_get_preferred_shell()); - char * shellname = g_path_get_basename(exec[0]); - exec[1] = g_strdup_printf("-%s", shellname); - g_free(shellname); - exec[2] = NULL; - term = terminal_new(terminal, label, proc_cwd, NULL, exec); - } - else - { - term = terminal_new(terminal, label, proc_cwd, NULL, NULL); - } + gint cmd_len = 0; + gchar * * exec = NULL; + if (cmd != NULL) + g_shell_parse_argv(cmd, &cmd_len, &exec, NULL); + terminal_process_requested_command(&exec, cmd_len, terminal->login_shell); + term = terminal_new(terminal, label, proc_cwd, NULL, exec); g_free(proc_cwd); /* Add a tab to the notebook and the "terms" array. */ @@ -1315,6 +1308,7 @@ static Term * terminal_new(LXTerminal * terminal, const gchar * label, const gch exec[1] = g_path_get_basename(exec[0]); exec[2] = NULL; } + term->command = exec; #if VTE_CHECK_VERSION (0, 38, 0) vte_terminal_spawn_sync( @@ -1342,7 +1336,6 @@ static Term * terminal_new(LXTerminal * terminal, const gchar * label, const gch &term->pid, NULL); #endif - g_strfreev(exec); /* Connect signals. */ g_signal_connect(G_OBJECT(term->tab), "button-press-event", G_CALLBACK(terminal_tab_button_press_event), term); @@ -1365,6 +1358,7 @@ static Term * terminal_new(LXTerminal * terminal, const gchar * label, const gch /* Deallocate a Term structure. */ static void terminal_free(Term * term) { + g_strfreev(term->command); g_free(term->matched_url); if ((GTK_IS_ACCEL_GROUP(term->parent->accel_group)) && (term->closure != NULL)) { @@ -1439,8 +1433,14 @@ gboolean lxterminal_process_arguments(gint argc, gchar * * argv, CommandArgument argv_cursor ++; char * argument = *argv_cursor; + /* --commands= */ + if (strncmp(argument, "--commands=", 11) == 0) + { + arguments->commands = &argument[11]; + } + /* --command= */ - if (strncmp(argument, "--command=", 10) == 0) + else if (strncmp(argument, "--command=", 10) == 0) { g_strfreev(arguments->command); g_shell_parse_argv(&argument[10], &cmd_len, &arguments->command, NULL); @@ -1450,7 +1450,7 @@ gboolean lxterminal_process_arguments(gint argc, gchar * * argv, CommandArgument * The behavior is demanded by distros who insist on this xterm feature. */ else if ((strcmp(argument, "--command") == 0) || (strcmp(argument, "-e") == 0)) { - if(arguments->command != NULL) g_strfreev(arguments->command); + g_strfreev(arguments->command); cmd_len = 0; arguments->command = g_malloc(argc * sizeof(gchar *)); @@ -1521,7 +1521,7 @@ gboolean lxterminal_process_arguments(gint argc, gchar * * argv, CommandArgument arguments->working_directory = &argument[20]; } - /* --no-remote: Do not accept or send remote commands */ + /* --no-remote: Do not accept or send remote commands */ else if (strcmp(argument, "--no-remote") == 0) { arguments->no_remote = TRUE; } @@ -1536,28 +1536,36 @@ gboolean lxterminal_process_arguments(gint argc, gchar * * argv, CommandArgument else { printf("%s\n", usage_display); return FALSE; + } } - } + terminal_process_requested_command(&arguments->command, cmd_len, arguments->login_shell); + return TRUE; +} + +/* Furthere process a command from the argument vector before executing it. */ +static void terminal_process_requested_command(gchar * * * const command, const gint cmd_len, const gboolean login_shell) +{ + gboolean force_login_shell = FALSE; /* Handle --loginshell. */ - if (arguments->command != NULL && cmd_len <= 2) { + if (*command != NULL && cmd_len <= 2) { /* Force using login shell if it has only 1 command, and command is not * in PATH. */ - gchar * program_path = g_find_program_in_path(arguments->command[0]); + gchar * program_path = g_find_program_in_path((*command)[0]); if (program_path == NULL) { - arguments->login_shell = TRUE; + force_login_shell = TRUE; } g_free(program_path); } - if (arguments->login_shell == TRUE) + if (login_shell == TRUE || force_login_shell == TRUE) { const gchar * shell = terminal_get_preferred_shell(); gchar * shellname = g_path_get_basename(shell); - if (arguments->command == NULL) + if (*command == NULL) { - arguments->command = g_malloc(3 * sizeof(gchar *)); - arguments->command[0] = g_strdup(shell); - arguments->command[1] = g_strdup_printf("-%s", shellname); - arguments->command[2] = NULL; + *command = g_malloc(3 * sizeof(gchar *)); + (*command)[0] = g_strdup(shell); + (*command)[1] = g_strdup_printf("-%s", shellname); + (*command)[2] = NULL; } else { @@ -1565,26 +1573,25 @@ gboolean lxterminal_process_arguments(gint argc, gchar * * argv, CommandArgument tmp[0] = g_strdup(shell); tmp[1] = g_strdup_printf("-%s", shellname); tmp[2] = g_strdup("-c"); - memcpy((tmp + 3), arguments->command, cmd_len * sizeof(gchar *)); + memcpy((tmp + 3), *command, cmd_len * sizeof(gchar *)); tmp[cmd_len + 3] = NULL; - g_free(arguments->command); - arguments->command = tmp; + g_free(*command); + *command = tmp; } g_free(shellname); } else { - if(arguments->command != NULL) + if (*command != NULL) { gchar * * tmp = g_malloc((cmd_len + 2) * sizeof(gchar *)); - tmp[0] = g_strdup(arguments->command[0]); - memcpy((tmp + 1), arguments->command, cmd_len * sizeof(gchar *)); + tmp[0] = g_strdup((*command)[0]); + memcpy((tmp + 1), *command, cmd_len * sizeof(gchar *)); tmp[cmd_len + 1] = NULL; - g_free(arguments->command); - arguments->command = tmp; + g_free(*command); + *command = tmp; } } - return TRUE; } /* Initialize a new LXTerminal. @@ -1670,12 +1677,28 @@ LXTerminal * lxterminal_initialize(LXTermWindow * lxtermwin, CommandArguments * { local_working_directory = g_get_current_dir(); } + gchar * first_comma = NULL;; + gboolean used_prefix_of_commands = FALSE; + if (arguments->command == NULL && arguments->commands != NULL) + { + used_prefix_of_commands = TRUE; + first_comma = strchr(arguments->commands, ','); + if (first_comma != NULL) + { + *first_comma = '\0'; + } + gint cmd_len = 0; + g_shell_parse_argv(arguments->commands, &cmd_len, &arguments->command, NULL); + terminal_process_requested_command(&arguments->command, cmd_len, arguments->login_shell); + } Term * term = terminal_new( terminal, ((arguments->title != NULL) ? arguments->title : NULL), ((arguments->working_directory != NULL) ? arguments->working_directory : local_working_directory), NULL, arguments->command); + if (first_comma != NULL) + *first_comma = ','; g_free(local_working_directory); /* Set window title. */ @@ -1761,18 +1784,36 @@ LXTerminal * lxterminal_initialize(LXTermWindow * lxtermwin, CommandArguments * /* Update terminal settings. */ terminal_settings_apply(terminal); - if (arguments->tabs != NULL && arguments->tabs[0] != '\0') + if (arguments->tabs != NULL && arguments->tabs[0] != '\0' || + arguments->commands != NULL && arguments->commands[0] != '\0') { - /* use token to destructively slice tabs to different tab names */ - char * token = strtok(arguments->tabs, ","); - term->user_specified_label = TRUE; - gtk_label_set_text(GTK_LABEL(term->label), token); - token = strtok(NULL, ","); + gchar * cmd = NULL, * cmd_saveptr, * tab = NULL, * tab_saveptr; + if (arguments->commands != NULL && arguments->commands[0] != '\0') + { + /* use cmd to destructively slice commands tab names */ + cmd = strtok_r(arguments->commands, ",", &cmd_saveptr); + if (used_prefix_of_commands == TRUE) + /* Initially, single hidden tab is running a command from --commands */ + cmd = strtok_r(NULL, ",", &cmd_saveptr); + } + if (arguments->tabs != NULL && arguments->tabs[0] != '\0') + { + /* use tab to destructively slice tabs to different tab names */ + tab = strtok_r(arguments->tabs, ",", &tab_saveptr); + term->user_specified_label = TRUE; + gtk_label_set_text(GTK_LABEL(term->label), tab); + /* Initially, a single tab is hidden */ + tab = strtok_r(NULL, ",", &tab_saveptr); + } - while (token != NULL && token[0] != '\0') + while (cmd != NULL && cmd[0] != '\0' || + tab != NULL && tab[0] != '\0') { - terminal_new_tab(terminal, token); - token = strtok(NULL, ","); + terminal_new_tab(terminal, tab, cmd); + if (cmd != NULL && cmd[0] != '\0') + cmd = strtok_r(NULL, ",", &cmd_saveptr); + if (tab != NULL && tab[0] != '\0') + tab = strtok_r(NULL, ",", &tab_saveptr); } } From f071b3fcb92d06c46c5da8869a3fa37e7be5b5da Mon Sep 17 00:00:00 2001 From: ZjYwMj <27451609+ZjYwMj@users.noreply.github.com> Date: Sat, 24 Jul 2021 17:00:14 +0000 Subject: [PATCH 3/3] [3/3] Update lxterminal.xml: new, run multiple commands from the command line Adds a new --commands= command line option. Note the s in commands. With the new command line option of --commands=, one can run multiple commands when starting lxterminal from the command line. Each command is automatically paired with a tab. After exhausting existing tabs, new tabs will be automatically created. This feature does not lift the basic limitation of commands in lxterminal command line. Which is, that short lived processes makes the tab they ran within, or the whole window in case of only short lived processes, to get closed as soon as the short lived processes has terminated. This limitation is shortly described in the modified man page. This patch constitutes of modifying 3 files: 1. src/lxterminal.h 2. src/lxterminal.c 3. man/lxterminal.xml The modification of lxterminal.xml, beside describing the new --commands= option, also describes, in some length, some pitfalls of lxterminal. --- man/lxterminal.xml | 66 ++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 58 insertions(+), 8 deletions(-) diff --git a/man/lxterminal.xml b/man/lxterminal.xml index d2859e00..f0622023 100644 --- a/man/lxterminal.xml +++ b/man/lxterminal.xml @@ -24,8 +24,7 @@ DESCRIPTION - This manual page documents briefly the - lxterminal command. + This manual page documents the lxterminal command. lxterminal is a program that provides a terminal emulator @@ -45,9 +44,9 @@ + - This option specifies the program (and its command line arguments) to be run in the terminal. -Except in the form, this must be the last option on the command line. + This option specifies the program (and its command line arguments) to be run in the terminal. Except in the , or the , forms, this must be the last option on the command line. Comma separated multiple commands create multiple tabs, each running a different comand, only with the form. New tabs will be created as necessary after all the explictly requested tabs will be exhausted. @@ -55,17 +54,24 @@ Except in the form, this must be the last option on Set the terminal's size in characters and lines. + + + + Prints a short help message, and exit. + + Executes login shell. - - - + + + + - Set the terminal's title. Use comma for multiple tabs. + Set the terminal's title. Comma separated multiple titles create multiple tabs only with the form. @@ -73,6 +79,50 @@ Except in the form, this must be the last option on Set the terminal's working directory. + + + + Prints the program version, and exit. + + + + + + EXAMPLES, AND MORE DETAILS + + + + A hidden tab is created when , or any variant, is requested, with no more than one command, or no more than one tab, is specified. For example, + lxterminal --tabs= --no-remote + This hidden tab can be revealed when the lxterminal is running. For example, when requesting a new tab with the Shift+Ctrl+T combination keys. + + + +For display puposes, the command examples might be broken into more than one line. When actually using the examples, commands should be entered in a single line. Or have line breaks according to the usual shell conventions. + All command examples here use to avoid interaction with possibly running lxterminals. + + + + Consider + lxterminal --no-remote --command='/bin/bash -c "echo This window will be closed after you will press enter. ; read -p \"Do press the <enter> key.\" " ' + This example emphasizes a limitaion of running commands from the lxterminal command line. As a result, the feature to run a command from the lxterminal command line is much more useful for processes that exit by the user explicit request. Such as an interactive shell. A short lived process does work. Only that it is fast enough to make the window, or the tab, closed before the user can pay attention. For a short lived process, such as + lxterminal --no-remote --command=ls + , the user must have indirect means to inspect the outcome. Such as redirecting the output to a file. + + + + + lxterminal --no-remote --tabs='1st tab',"2nd tab" --tabs= --no-remote + In contrast to many other applications, repeating a command line is not an error. With some s, the last repetition override previous ocuurences. But there are exceptions. A will always be executed in the 1st tab. Before, and in addition to, any . Just try out if it is a concern for you. The behaviour is deterministic. + + + + + Comma characters, ',', are used as separators for the , and options. + lxterminal --tabs="midnight commander,2nd tab" --commands='mc, ' --no-remote + There is no way to insert a comma character in the titles to be displayed by . Or in the programs, and their arguments, to be run by . However, the single , and its other variants, can accept a comma character as part of the program, and its arguments, to be executed. + +