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.
+
+
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);
}
}
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;