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;