[gnome-builder/wip/gtk4-port] libide/terminal: rebuild terminal launches on run commands
- From: Christian Hergert <chergert src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-builder/wip/gtk4-port] libide/terminal: rebuild terminal launches on run commands
- Date: Tue, 28 Jun 2022 00:17:29 +0000 (UTC)
commit a367cf0cbf51777f03f9e8532ec8109a77de302e
Author: Christian Hergert <chergert redhat com>
Date: Mon Jun 27 17:17:19 2022 -0700
libide/terminal: rebuild terminal launches on run commands
This allows us to simplify a whole lot of code and delete all the
divergance in terminal launchers.
src/libide/gui/ide-frame.ui | 3 +-
src/libide/terminal/ide-terminal-launcher.c | 859 +++------------------
src/libide/terminal/ide-terminal-launcher.h | 57 +-
src/libide/terminal/ide-terminal-page.c | 46 +-
src/libide/terminal/ide-terminal-page.h | 2 +
src/libide/terminal/ide-terminal-private.h | 6 +-
.../terminal/ide-terminal-run-command-private.h | 43 ++
src/libide/terminal/ide-terminal-run-command.c | 142 ++++
src/libide/terminal/meson.build | 2 +
src/plugins/shellcmd/gbp-shellcmd-run-command.c | 93 ---
src/plugins/shellcmd/gbp-shellcmd-run-command.h | 2 -
.../shellcmd/gbp-shellcmd-shortcut-provider.c | 13 +-
.../terminal/gbp-terminal-workspace-addin.c | 391 ++++------
src/plugins/terminal/gtk/keybindings.json | 6 +-
src/plugins/terminal/gtk/menus.ui | 16 +-
15 files changed, 491 insertions(+), 1190 deletions(-)
---
diff --git a/src/libide/gui/ide-frame.ui b/src/libide/gui/ide-frame.ui
index 90e978f9d..8c9e363e2 100644
--- a/src/libide/gui/ide-frame.ui
+++ b/src/libide/gui/ide-frame.ui
@@ -108,7 +108,8 @@
<child>
<object class="GtkButton">
<property name="label" translatable="yes">New Terminal</property>
- <property name="action-name">win.new-terminal</property>
+ <property name="action-name">terminal.terminal-on-host</property>
+ <property name="action-target">''</property>
</object>
</child>
</object>
diff --git a/src/libide/terminal/ide-terminal-launcher.c b/src/libide/terminal/ide-terminal-launcher.c
index cc98d82f3..728727f4a 100644
--- a/src/libide/terminal/ide-terminal-launcher.c
+++ b/src/libide/terminal/ide-terminal-launcher.c
@@ -23,176 +23,31 @@
#include "config.h"
#include <errno.h>
+
#include <glib/gi18n.h>
+
#include <libide-foundry.h>
#include <libide-threading.h>
-#include "ide-private.h"
-
#include "ide-terminal-launcher.h"
-#include "ide-terminal-private.h"
-#include "ide-terminal-util.h"
-
-typedef enum
-{
- LAUNCHER_KIND_HOST = 0,
- LAUNCHER_KIND_DEBUG,
- LAUNCHER_KIND_RUNTIME,
- LAUNCHER_KIND_RUNNER,
- LAUNCHER_KIND_LAUNCHER,
- LAUNCHER_KIND_CONFIG,
-} LauncherKind;
struct _IdeTerminalLauncher
{
- GObject parent_instance;
- gchar *cwd;
- gchar *shell;
- gchar *title;
- gchar **args;
- IdeRuntime *runtime;
- IdeContext *context;
- IdeConfig *config;
- IdeSubprocessLauncher *launcher;
- LauncherKind kind;
+ GObject parent_instance;
+ IdeRunCommand *run_command;
+ IdeContext *context;
};
G_DEFINE_FINAL_TYPE (IdeTerminalLauncher, ide_terminal_launcher, G_TYPE_OBJECT)
enum {
PROP_0,
- PROP_ARGS,
- PROP_CWD,
- PROP_SHELL,
- PROP_TITLE,
+ PROP_CONTEXT,
+ PROP_RUN_COMMAND,
N_PROPS
};
static GParamSpec *properties [N_PROPS];
-static const struct {
- const gchar *key;
- const gchar *value;
-} default_environment[] = {
- { "INSIDE_GNOME_BUILDER", PACKAGE_VERSION },
- { "TERM", "xterm-256color" },
-};
-
-static gboolean
-shell_supports_login (const gchar *shell)
-{
- g_autofree gchar *name = NULL;
-
- /* Shells that support --login */
- static const gchar *supported[] = {
- "sh", "bash",
- };
-
- if (shell == NULL)
- return FALSE;
-
- if (!(name = g_path_get_basename (shell)))
- return FALSE;
-
- for (guint i = 0; i < G_N_ELEMENTS (supported); i++)
- {
- if (g_str_equal (name, supported[i]))
- return TRUE;
- }
-
- return FALSE;
-}
-
-static void
-copy_envvars (gpointer instance)
-{
- static const gchar *copy_env[] = {
- "AT_SPI_BUS_ADDRESS",
- "COLORTERM",
- "DBUS_SESSION_BUS_ADDRESS",
- "DBUS_SYSTEM_BUS_ADDRESS",
- "DESKTOP_SESSION",
- "DISPLAY",
- "LANG",
- "SHELL",
- "SSH_AUTH_SOCK",
- "USER",
- "WAYLAND_DISPLAY",
- "XAUTHORITY",
- "XDG_CURRENT_DESKTOP",
-#if 0
- /* Can't copy these as they could mess up Flatpak */
- "XDG_DATA_DIRS",
- "XDG_RUNTIME_DIR",
-#endif
- "XDG_MENU_PREFIX",
- "XDG_SEAT",
- "XDG_SESSION_DESKTOP",
- "XDG_SESSION_ID",
- "XDG_SESSION_TYPE",
- "XDG_VTNR",
- };
- const gchar * const *host_environ;
- IdeEnvironment *env = NULL;
-
- g_assert (IDE_IS_SUBPROCESS_LAUNCHER (instance) || IDE_IS_RUNNER (instance));
-
- if (IDE_IS_RUNNER (instance))
- env = ide_runner_get_environment (instance);
-
- host_environ = _ide_host_environ ();
-
- for (guint i = 0; i < G_N_ELEMENTS (copy_env); i++)
- {
- const gchar *val = g_environ_getenv ((gchar **)host_environ, copy_env[i]);
-
- if (val != NULL)
- {
- if (IDE_IS_SUBPROCESS_LAUNCHER (instance))
- ide_subprocess_launcher_setenv (instance, copy_env[i], val, FALSE);
- else
- ide_environment_setenv (env, copy_env[i], val);
- }
- }
-}
-
-static void
-apply_pipeline_info (gpointer instance,
- IdeObject *object)
-{
- g_autoptr(GFile) workdir = NULL;
- IdeEnvironment *env = NULL;
- IdeContext *context;
-
- g_assert (IDE_IS_SUBPROCESS_LAUNCHER (instance) || IDE_IS_RUNNER (instance));
- g_assert (IDE_IS_OBJECT (object));
-
- context = ide_object_get_context (object);
- workdir = ide_context_ref_workdir (context);
-
- if (IDE_IS_RUNNER (instance))
- env = ide_runner_get_environment (instance);
-
- if (IDE_IS_SUBPROCESS_LAUNCHER (instance))
- ide_subprocess_launcher_setenv (instance, "SRCDIR", g_file_peek_path (workdir), FALSE);
- else
- ide_environment_setenv (env, "SRCDIR", g_file_peek_path (workdir));
-
- if (ide_context_has_project (context))
- {
- IdeBuildManager *build_manager = ide_build_manager_from_context (context);
- IdePipeline *pipeline = ide_build_manager_get_pipeline (build_manager);
-
- if (pipeline != NULL)
- {
- const gchar *builddir = ide_pipeline_get_builddir (pipeline);
-
- if (IDE_IS_SUBPROCESS_LAUNCHER (instance))
- ide_subprocess_launcher_setenv (instance, "BUILDDIR", builddir, FALSE);
- else
- ide_environment_setenv (env, "BUILDDIR", builddir);
- }
- }
-}
static void
ide_terminal_launcher_wait_check_cb (GObject *object,
@@ -203,6 +58,9 @@ ide_terminal_launcher_wait_check_cb (GObject *object,
g_autoptr(IdeTask) task = user_data;
g_autoptr(GError) error = NULL;
+ IDE_ENTRY;
+
+ g_assert (IDE_IS_MAIN_THREAD ());
g_assert (IDE_IS_SUBPROCESS (subprocess));
g_assert (G_IS_ASYNC_RESULT (result));
g_assert (IDE_IS_TASK (task));
@@ -211,281 +69,8 @@ ide_terminal_launcher_wait_check_cb (GObject *object,
ide_task_return_error (task, g_steal_pointer (&error));
else
ide_task_return_boolean (task, TRUE);
-}
-
-static void
-spawn_host_launcher (IdeTerminalLauncher *self,
- IdeTask *task,
- gint pty_fd,
- gboolean run_on_host)
-{
- g_autoptr(IdeSubprocessLauncher) launcher = NULL;
- g_autoptr(IdeSubprocess) subprocess = NULL;
- g_autoptr(GError) error = NULL;
- const gchar *shell;
-
- g_assert (IDE_IS_TERMINAL_LAUNCHER (self));
- g_assert (IDE_IS_TASK (task));
- g_assert (pty_fd >= 0);
-
- if (!(shell = ide_terminal_launcher_get_shell (self)))
- shell = ide_get_user_shell ();
-
- /* We only have sh/bash in our flatpak */
- if (self->kind == LAUNCHER_KIND_DEBUG && ide_is_flatpak ())
- shell = "/bin/bash";
-
- launcher = ide_subprocess_launcher_new (0);
- ide_subprocess_launcher_set_run_on_host (launcher, run_on_host);
- ide_subprocess_launcher_set_cwd (launcher, self->cwd ? self->cwd : g_get_home_dir ());
- ide_subprocess_launcher_set_clear_env (launcher, FALSE);
-
- ide_subprocess_launcher_push_argv (launcher, shell);
- if (shell_supports_login (shell))
- ide_subprocess_launcher_push_argv (launcher, "--login");
-
- ide_subprocess_launcher_take_stdin_fd (launcher, dup (pty_fd));
- ide_subprocess_launcher_take_stdout_fd (launcher, dup (pty_fd));
- ide_subprocess_launcher_take_stderr_fd (launcher, dup (pty_fd));
-
- g_assert (ide_subprocess_launcher_get_needs_tty (launcher));
-
- for (guint i = 0; i < G_N_ELEMENTS (default_environment); i++)
- ide_subprocess_launcher_setenv (launcher,
- default_environment[i].key,
- default_environment[i].value,
- FALSE);
-
- ide_subprocess_launcher_setenv (launcher, "SHELL", shell, TRUE);
-
- if (self->context != NULL)
- {
- g_autoptr(GFile) workdir = ide_context_ref_workdir (self->context);
-
- ide_subprocess_launcher_setenv (launcher,
- "SRCDIR",
- g_file_peek_path (workdir),
- FALSE);
- }
-
- if (!(subprocess = ide_subprocess_launcher_spawn (launcher, NULL, &error)))
- ide_task_return_error (task, g_steal_pointer (&error));
- else
- ide_subprocess_wait_check_async (subprocess,
- ide_task_get_cancellable (task),
- ide_terminal_launcher_wait_check_cb,
- g_object_ref (task));
-}
-
-static void
-spawn_launcher (IdeTerminalLauncher *self,
- IdeTask *task,
- IdeSubprocessLauncher *launcher,
- gint pty_fd)
-{
- g_autoptr(IdeSubprocess) subprocess = NULL;
- g_autoptr(GError) error = NULL;
-
- g_assert (IDE_IS_TERMINAL_LAUNCHER (self));
- g_assert (IDE_IS_TASK (task));
- g_assert (!launcher || IDE_IS_SUBPROCESS_LAUNCHER (launcher));
- g_assert (pty_fd >= 0);
-
- if (launcher == NULL)
- {
- ide_task_return_new_error (task,
- G_IO_ERROR,
- G_IO_ERROR_FAILED,
- "process may only be spawned once");
- return;
- }
-
- ide_subprocess_launcher_set_flags (launcher, 0);
-
- ide_subprocess_launcher_take_stdin_fd (launcher, dup (pty_fd));
- ide_subprocess_launcher_take_stdout_fd (launcher, dup (pty_fd));
- ide_subprocess_launcher_take_stderr_fd (launcher, dup (pty_fd));
-
- if (!(subprocess = ide_subprocess_launcher_spawn (launcher, NULL, &error)))
- ide_task_return_error (task, g_steal_pointer (&error));
- else
- ide_subprocess_wait_check_async (subprocess,
- ide_task_get_cancellable (task),
- ide_terminal_launcher_wait_check_cb,
- g_object_ref (task));
-}
-
-static void
-spawn_runtime_launcher (IdeTerminalLauncher *self,
- IdeTask *task,
- IdeRuntime *runtime,
- IdeConfig *config,
- gint pty_fd)
-{
- g_autoptr(IdeSubprocessLauncher) launcher = NULL;
- g_autoptr(IdeSubprocess) subprocess = NULL;
- g_autoptr(GError) error = NULL;
- const gchar *shell;
-
- g_assert (IDE_IS_TERMINAL_LAUNCHER (self));
- g_assert (IDE_IS_TASK (task));
- g_assert (!runtime || IDE_IS_RUNTIME (runtime));
- g_assert (pty_fd >= 0);
-
- if (runtime == NULL)
- {
- ide_task_return_new_error (task,
- G_IO_ERROR,
- G_IO_ERROR_FAILED,
- _("Requested runtime is not installed"));
- return;
- }
-
- if (!(shell = ide_terminal_launcher_get_shell (self)))
- shell = ide_get_user_shell ();
-
- if (!(launcher = ide_runtime_create_launcher (runtime, NULL)))
- {
- ide_task_return_new_error (task,
- G_IO_ERROR,
- G_IO_ERROR_FAILED,
- _("Failed to create shell within runtime ā%sā"),
- ide_runtime_get_display_name (runtime));
- return;
- }
-
- ide_subprocess_launcher_set_flags (launcher, 0);
-
- if (!ide_runtime_contains_program_in_path (runtime, shell, NULL))
- shell = "/bin/sh";
-
- ide_subprocess_launcher_set_cwd (launcher, self->cwd ? self->cwd : g_get_home_dir ());
-
- ide_subprocess_launcher_push_argv (launcher, shell);
- if (shell_supports_login (shell))
- ide_subprocess_launcher_push_argv (launcher, "--login");
-
- ide_subprocess_launcher_take_stdin_fd (launcher, dup (pty_fd));
- ide_subprocess_launcher_take_stdout_fd (launcher, dup (pty_fd));
- ide_subprocess_launcher_take_stderr_fd (launcher, dup (pty_fd));
-
- g_assert (ide_subprocess_launcher_get_needs_tty (launcher));
-
- for (guint i = 0; i < G_N_ELEMENTS (default_environment); i++)
- ide_subprocess_launcher_setenv (launcher,
- default_environment[i].key,
- default_environment[i].value,
- FALSE);
-
- apply_pipeline_info (launcher, IDE_OBJECT (self->runtime));
- copy_envvars (launcher);
-
- ide_subprocess_launcher_setenv (launcher, "SHELL", shell, TRUE);
-
- if (config != NULL)
- ide_config_apply_path (config, launcher);
-
- if (!(subprocess = ide_subprocess_launcher_spawn (launcher, NULL, &error)))
- ide_task_return_error (task, g_steal_pointer (&error));
- else
- ide_subprocess_wait_check_async (subprocess,
- ide_task_get_cancellable (task),
- ide_terminal_launcher_wait_check_cb,
- g_object_ref (task));
-}
-
-static void
-ide_terminal_launcher_run_cb (GObject *object,
- GAsyncResult *result,
- gpointer user_data)
-{
- IdeRunner *runner = (IdeRunner *)object;
- g_autoptr(IdeTask) task = user_data;
- g_autoptr(GError) error = NULL;
-
- g_assert (IDE_IS_RUNNER (runner));
- g_assert (G_IS_ASYNC_RESULT (result));
- g_assert (IDE_IS_TASK (task));
-
- if (!ide_runner_run_finish (runner, result, &error))
- ide_task_return_error (task, g_steal_pointer (&error));
- else
- ide_task_return_boolean (task, TRUE);
- ide_object_destroy (IDE_OBJECT (runner));
-}
-
-static void
-spawn_runner_launcher (IdeTerminalLauncher *self,
- IdeTask *task,
- IdeRuntime *runtime,
- gint pty_fd)
-{
- g_autoptr(IdeSimpleBuildTarget) build_target = NULL;
- g_autoptr(IdeRunner) runner = NULL;
- g_autoptr(GPtrArray) argv = NULL;
- IdeEnvironment *env;
- const gchar *shell;
-
- g_assert (IDE_IS_TERMINAL_LAUNCHER (self));
- g_assert (IDE_IS_TASK (task));
- g_assert (!runtime || IDE_IS_RUNTIME (runtime));
- g_assert (pty_fd >= 0);
-
- if (runtime == NULL)
- {
- ide_task_return_new_error (task,
- G_IO_ERROR,
- G_IO_ERROR_FAILED,
- _("Requested runtime is not installed"));
- return;
- }
-
- if (!(shell = ide_terminal_launcher_get_shell (self)))
- shell = ide_get_user_shell ();
-
- if (!ide_runtime_contains_program_in_path (runtime, shell, NULL))
- shell = "/bin/sh";
-
- argv = g_ptr_array_new ();
- g_ptr_array_add (argv, (gchar *)shell);
-
- if (self->args == NULL)
- {
- if (shell_supports_login (shell))
- g_ptr_array_add (argv, (gchar *)"--login");
- }
- else
- {
- for (guint i = 0; self->args[i]; i++)
- g_ptr_array_add (argv, self->args[i]);
- }
-
- g_ptr_array_add (argv, NULL);
-
- build_target = ide_simple_build_target_new (NULL);
- ide_simple_build_target_set_argv (build_target, (const gchar * const *)argv->pdata);
- ide_simple_build_target_set_cwd (build_target, self->cwd ? self->cwd : g_get_home_dir ());
-
- /* Creating runner should always succeed, but run_async() may fail */
- runner = ide_runtime_create_runner (runtime, IDE_BUILD_TARGET (build_target));
- env = ide_runner_get_environment (runner);
- ide_runner_take_tty_fd (runner, dup (pty_fd));
-
- for (guint i = 0; i < G_N_ELEMENTS (default_environment); i++)
- ide_environment_setenv (env,
- default_environment[i].key,
- default_environment[i].value);
-
- apply_pipeline_info (runner, IDE_OBJECT (self->runtime));
- copy_envvars (runner);
-
- ide_environment_setenv (env, "SHELL", shell);
-
- ide_runner_run_async (runner,
- ide_task_get_cancellable (task),
- ide_terminal_launcher_run_cb,
- g_object_ref (task));
+ IDE_EXIT;
}
void
@@ -495,9 +80,14 @@ ide_terminal_launcher_spawn_async (IdeTerminalLauncher *self,
GAsyncReadyCallback callback,
gpointer user_data)
{
+ g_autoptr(IdeRunContext) run_context = NULL;
+ g_autoptr(IdeSubprocess) subprocess = NULL;
g_autoptr(IdeTask) task = NULL;
- gint pty_fd = -1;
+ g_autoptr(GError) error = NULL;
+
+ IDE_ENTRY;
+ g_assert (IDE_IS_MAIN_THREAD ());
g_assert (IDE_IS_TERMINAL_LAUNCHER (self));
g_assert (VTE_IS_PTY (pty));
g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
@@ -505,44 +95,38 @@ ide_terminal_launcher_spawn_async (IdeTerminalLauncher *self,
task = ide_task_new (self, cancellable, callback, user_data);
ide_task_set_source_tag (task, ide_terminal_launcher_spawn_async);
- if ((pty_fd = ide_vte_pty_create_producer (pty)) == -1)
+ run_context = ide_run_context_new ();
+
+ /* Paranoia check to ensure we've been constructed right */
+ if (self->run_command == NULL || self->context == NULL)
{
- int errsv = errno;
ide_task_return_new_error (task,
G_IO_ERROR,
- g_io_error_from_errno (errsv),
- "%s", g_strerror (errsv));
- return;
+ G_IO_ERROR_NOT_INITIALIZED,
+ "%s is improperly configured",
+ G_OBJECT_TYPE_NAME (self));
+ IDE_EXIT;
}
- switch (self->kind)
- {
- case LAUNCHER_KIND_RUNTIME:
- spawn_runtime_launcher (self, task, self->runtime, NULL, pty_fd);
- break;
-
- case LAUNCHER_KIND_CONFIG:
- spawn_runtime_launcher (self, task, self->runtime, self->config, pty_fd);
- break;
+ ide_run_command_prepare_to_run (self->run_command, run_context, self->context);
- case LAUNCHER_KIND_RUNNER:
- spawn_runner_launcher (self, task, self->runtime, pty_fd);
- break;
+ /* Add some environment for custom bashrc, VTE, etc */
+ ide_run_context_setenv (run_context, "INSIDE_GNOME_BUILDER", PACKAGE_VERSION);
+ ide_run_context_setenv (run_context, "TERM", "xterm-256color");
- case LAUNCHER_KIND_LAUNCHER:
- spawn_launcher (self, task, self->launcher, pty_fd);
- g_clear_object (&self->launcher);
- break;
+ /* Attach the PTY to stdin/stdout/stderr */
+ ide_run_context_set_pty (run_context, pty);
- case LAUNCHER_KIND_DEBUG:
- case LAUNCHER_KIND_HOST:
- default:
- spawn_host_launcher (self, task, pty_fd, self->kind == LAUNCHER_KIND_HOST);
- break;
- }
+ /* Now attempt to spawn the process */
+ if (!(subprocess = ide_run_context_spawn (run_context, &error)))
+ ide_task_return_error (task, g_steal_pointer (&error));
+ else
+ ide_subprocess_wait_check_async (subprocess,
+ cancellable,
+ ide_terminal_launcher_wait_check_cb,
+ g_steal_pointer (&task));
- if (pty_fd != -1)
- close (pty_fd);
+ IDE_EXIT;
}
/**
@@ -559,26 +143,27 @@ ide_terminal_launcher_spawn_finish (IdeTerminalLauncher *self,
GAsyncResult *result,
GError **error)
{
+ gboolean ret;
+
+ IDE_ENTRY;
+
g_assert (IDE_IS_TERMINAL_LAUNCHER (self));
g_assert (IDE_IS_TASK (result));
- return ide_task_propagate_boolean (IDE_TASK (result), error);
+ ret = ide_task_propagate_boolean (IDE_TASK (result), error);
+
+ IDE_RETURN (ret);
}
static void
-ide_terminal_launcher_finalize (GObject *object)
+ide_terminal_launcher_dispose (GObject *object)
{
IdeTerminalLauncher *self = (IdeTerminalLauncher *)object;
- g_clear_pointer (&self->args, g_strfreev);
- g_clear_pointer (&self->cwd, g_free);
- g_clear_pointer (&self->shell, g_free);
- g_clear_pointer (&self->title, g_free);
- g_clear_object (&self->launcher);
- g_clear_object (&self->runtime);
- g_clear_object (&self->config);
+ g_clear_object (&self->context);
+ g_clear_object (&self->run_command);
- G_OBJECT_CLASS (ide_terminal_launcher_parent_class)->finalize (object);
+ G_OBJECT_CLASS (ide_terminal_launcher_parent_class)->dispose (object);
}
static void
@@ -591,20 +176,12 @@ ide_terminal_launcher_get_property (GObject *object,
switch (prop_id)
{
- case PROP_ARGS:
- g_value_set_boxed (value, ide_terminal_launcher_get_args (self));
- break;
-
- case PROP_CWD:
- g_value_set_string (value, ide_terminal_launcher_get_cwd (self));
- break;
-
- case PROP_SHELL:
- g_value_set_string (value, ide_terminal_launcher_get_shell (self));
+ case PROP_CONTEXT:
+ g_value_set_object (value, self->context);
break;
- case PROP_TITLE:
- g_value_set_string (value, ide_terminal_launcher_get_title (self));
+ case PROP_RUN_COMMAND:
+ g_value_set_object (value, self->run_command);
break;
default:
@@ -622,20 +199,12 @@ ide_terminal_launcher_set_property (GObject *object,
switch (prop_id)
{
- case PROP_ARGS:
- ide_terminal_launcher_set_args (self, g_value_get_boxed (value));
- break;
-
- case PROP_CWD:
- ide_terminal_launcher_set_cwd (self, g_value_get_string (value));
- break;
-
- case PROP_SHELL:
- ide_terminal_launcher_set_shell (self, g_value_get_string (value));
+ case PROP_CONTEXT:
+ g_set_object (&self->context, g_value_get_object (value));
break;
- case PROP_TITLE:
- ide_terminal_launcher_set_title (self, g_value_get_string (value));
+ case PROP_RUN_COMMAND:
+ g_set_object (&self->run_command, g_value_get_object (value));
break;
default:
@@ -648,36 +217,22 @@ ide_terminal_launcher_class_init (IdeTerminalLauncherClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
- object_class->finalize = ide_terminal_launcher_finalize;
+ object_class->dispose = ide_terminal_launcher_dispose;
object_class->get_property = ide_terminal_launcher_get_property;
object_class->set_property = ide_terminal_launcher_set_property;
- properties [PROP_ARGS] =
- g_param_spec_boxed ("args",
- "Args",
- "Arguments to shell",
- G_TYPE_STRV,
- (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-
- properties [PROP_CWD] =
- g_param_spec_string ("cwd",
- "Cwd",
- "The cwd to spawn in the subprocess",
- NULL,
- (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-
- properties [PROP_SHELL] =
- g_param_spec_string ("shell",
- "Shell",
- "The shell to spawn in the subprocess",
- NULL,
- (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-
- properties [PROP_TITLE] =
- g_param_spec_string ("title",
- "Title",
- "The title for the subprocess launcher",
- NULL,
+ properties [PROP_CONTEXT] =
+ g_param_spec_object ("context",
+ "Context",
+ "The context for the launcher",
+ IDE_TYPE_CONTEXT,
+ (G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
+
+ properties [PROP_RUN_COMMAND] =
+ g_param_spec_object ("run-command",
+ "Run Command",
+ "The run command to spawn",
+ IDE_TYPE_RUN_COMMAND,
(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_properties (object_class, N_PROPS, properties);
@@ -686,279 +241,45 @@ ide_terminal_launcher_class_init (IdeTerminalLauncherClass *klass)
static void
ide_terminal_launcher_init (IdeTerminalLauncher *self)
{
- self->cwd = NULL;
- self->shell = NULL;
- self->title = g_strdup (_("Untitled Terminal"));
-}
-
-const gchar *
-ide_terminal_launcher_get_cwd (IdeTerminalLauncher *self)
-{
- g_return_val_if_fail (IDE_IS_TERMINAL_LAUNCHER (self), NULL);
-
- return self->cwd;
-}
-
-void
-ide_terminal_launcher_set_cwd (IdeTerminalLauncher *self,
- const gchar *cwd)
-{
- g_return_if_fail (IDE_IS_TERMINAL_LAUNCHER (self));
-
- if (g_strcmp0 (self->cwd, cwd) != 0)
- {
- g_free (self->cwd);
- self->cwd = g_strdup (cwd);
- g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_CWD]);
- }
-}
-
-const gchar *
-ide_terminal_launcher_get_shell (IdeTerminalLauncher *self)
-{
- g_return_val_if_fail (IDE_IS_TERMINAL_LAUNCHER (self), NULL);
-
- return self->shell;
-}
-
-void
-ide_terminal_launcher_set_shell (IdeTerminalLauncher *self,
- const gchar *shell)
-{
- g_return_if_fail (IDE_IS_TERMINAL_LAUNCHER (self));
-
- if (g_strcmp0 (self->shell, shell) != 0)
- {
- g_free (self->shell);
- self->shell = g_strdup (shell);
- g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_SHELL]);
- }
-}
-
-const gchar *
-ide_terminal_launcher_get_title (IdeTerminalLauncher *self)
-{
- g_return_val_if_fail (IDE_IS_TERMINAL_LAUNCHER (self), NULL);
-
- return self->title;
-}
-
-void
-ide_terminal_launcher_set_title (IdeTerminalLauncher *self,
- const gchar *title)
-{
- g_return_if_fail (IDE_IS_TERMINAL_LAUNCHER (self));
-
- if (g_strcmp0 (self->title, title) != 0)
- {
- g_free (self->title);
- self->title = g_strdup (title);
- g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_TITLE]);
- }
}
/**
* ide_terminal_launcher_new:
+ * @context: an #IdeContext
+ * @run_command: an #IdeRunCommand to spawn
*
- * Create a new #IdeTerminalLauncher that will spawn a terminal on the host.
+ * Create an #IdeTerminalLauncher that spawns @run_command.
*
* Returns: (transfer full): a newly created #IdeTerminalLauncher
*/
IdeTerminalLauncher *
-ide_terminal_launcher_new (IdeContext *context)
+ide_terminal_launcher_new (IdeContext *context,
+ IdeRunCommand *run_command)
{
- IdeTerminalLauncher *self;
- g_autoptr(GFile) workdir = NULL;
-
g_return_val_if_fail (IDE_IS_CONTEXT (context), NULL);
+ g_return_val_if_fail (IDE_IS_RUN_COMMAND (run_command), NULL);
- workdir = ide_context_ref_workdir (context);
-
- self = g_object_new (IDE_TYPE_TERMINAL_LAUNCHER, NULL);
- self->kind = LAUNCHER_KIND_HOST;
- self->cwd = g_file_get_path (workdir);
- self->context = g_object_ref (context);
-
- return g_steal_pointer (&self);
+ return g_object_new (IDE_TYPE_TERMINAL_LAUNCHER,
+ "context", context,
+ "run-command", run_command,
+ NULL);
}
/**
- * ide_terminal_launcher_new_for_launcher:
- * @launcher: an #IdeSubprocessLauncher
+ * ide_terminal_launcher_copy:
+ * @self: an #IdeTerminalLauncher
*
- * Creates a new #IdeTerminalLauncher that can be used to launch a process
- * using the provided #IdeSubprocessLauncher.
- *
- * Returns: (transfer full): an #IdeTerminalLauncher
- */
-IdeTerminalLauncher *
-ide_terminal_launcher_new_for_launcher (IdeSubprocessLauncher *launcher)
-{
- IdeTerminalLauncher *self;
-
- g_return_val_if_fail (IDE_IS_SUBPROCESS_LAUNCHER (launcher), NULL);
-
- self = g_object_new (IDE_TYPE_TERMINAL_LAUNCHER, NULL);
- self->kind = LAUNCHER_KIND_LAUNCHER;
- self->launcher = g_object_ref (launcher);
-
- return g_steal_pointer (&self);
-}
-
-/**
- * ide_terminal_launcher_new_for_debug
- *
- * Create a new #IdeTerminalLauncher that will spawn a terminal on the host.
- *
- * Returns: (transfer full): a newly created #IdeTerminalLauncher
- */
-IdeTerminalLauncher *
-ide_terminal_launcher_new_for_debug (void)
-{
- IdeTerminalLauncher *self;
-
- self = g_object_new (IDE_TYPE_TERMINAL_LAUNCHER, NULL);
- self->kind = LAUNCHER_KIND_DEBUG;
-
- return g_steal_pointer (&self);
-}
-
-/**
- * ide_terminal_launcher_new_for_config:
- * @config: an #IdeConfig
- *
- * Create a new #IdeTerminalLauncher that will spawn a terminal in the runtime
- * of the configuration with various build options applied.
+ * Copies @self into a new launcher.
*
* Returns: (transfer full): a newly created #IdeTerminalLauncher
*/
IdeTerminalLauncher *
-ide_terminal_launcher_new_for_config (IdeConfig *config)
-{
- IdeTerminalLauncher *self;
- IdeRuntime *runtime;
-
- g_return_val_if_fail (IDE_IS_CONFIG (config), NULL);
-
- runtime = ide_config_get_runtime (config);
-
- self = g_object_new (IDE_TYPE_TERMINAL_LAUNCHER, NULL);
- self->runtime = g_object_ref (runtime);
- self->config = g_object_ref (config);
- self->kind = LAUNCHER_KIND_CONFIG;
-
- ide_terminal_launcher_set_title (self, ide_runtime_get_name (runtime));
-
- return g_steal_pointer (&self);
-}
-
-/**
- * ide_terminal_launcher_new_for_runtime:
- * @runtime: an #IdeRuntime
- *
- * Create a new #IdeTerminalLauncher that will spawn a terminal in the runtime.
- *
- * Returns: (transfer full): a newly created #IdeTerminalLauncher
- */
-IdeTerminalLauncher *
-ide_terminal_launcher_new_for_runtime (IdeRuntime *runtime)
-{
- IdeTerminalLauncher *self;
-
- g_return_val_if_fail (IDE_IS_RUNTIME (runtime), NULL);
-
- self = g_object_new (IDE_TYPE_TERMINAL_LAUNCHER, NULL);
- self->runtime = g_object_ref (runtime);
- self->kind = LAUNCHER_KIND_RUNTIME;
-
- ide_terminal_launcher_set_title (self, ide_runtime_get_name (runtime));
-
- return g_steal_pointer (&self);
-}
-
-/**
- * ide_terminal_launcher_new_for_runner:
- * @runtime: an #IdeRuntime
- *
- * Create a new #IdeTerminalLauncher that will spawn a terminal in the runtime
- * but with a "runner" context similar to how the application would execute.
- *
- * Returns: (transfer full): a newly created #IdeTerminalLauncher
- */
-IdeTerminalLauncher *
-ide_terminal_launcher_new_for_runner (IdeRuntime *runtime)
-{
- IdeTerminalLauncher *self;
-
- g_return_val_if_fail (IDE_IS_RUNTIME (runtime), NULL);
-
- self = g_object_new (IDE_TYPE_TERMINAL_LAUNCHER, NULL);
- self->runtime = g_object_ref (runtime);
- self->kind = LAUNCHER_KIND_RUNNER;
-
- ide_terminal_launcher_set_title (self, ide_runtime_get_name (runtime));
-
- return g_steal_pointer (&self);
-}
-
-gboolean
-ide_terminal_launcher_can_respawn (IdeTerminalLauncher *self)
-{
- g_return_val_if_fail (IDE_IS_TERMINAL_LAUNCHER (self), FALSE);
-
- return self->kind != LAUNCHER_KIND_LAUNCHER;
-}
-
-const gchar * const *
-ide_terminal_launcher_get_args (IdeTerminalLauncher *self)
+ide_terminal_launcher_copy (IdeTerminalLauncher *self)
{
g_return_val_if_fail (IDE_IS_TERMINAL_LAUNCHER (self), NULL);
- return (const gchar * const *)self->args;
-}
-
-void
-ide_terminal_launcher_set_args (IdeTerminalLauncher *self,
- const gchar * const *args)
-{
- g_return_if_fail (IDE_IS_TERMINAL_LAUNCHER (self));
-
- if ((gchar **)args != self->args)
- {
- gchar **freeme = g_steal_pointer (&self->args);
- self->args = g_strdupv ((gchar **)args);
- g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_ARGS]);
- g_strfreev (freeme);
- }
-}
-
-gboolean
-_ide_terminal_launcher_are_similar (IdeTerminalLauncher *a,
- IdeTerminalLauncher *b)
-{
- g_return_val_if_fail (IDE_IS_TERMINAL_LAUNCHER (a), FALSE);
- g_return_val_if_fail (IDE_IS_TERMINAL_LAUNCHER (b), FALSE);
-
- if (a->kind != b->kind)
- return FALSE;
-
- switch (a->kind)
- {
- case LAUNCHER_KIND_HOST:
- case LAUNCHER_KIND_DEBUG:
- return TRUE;
-
- case LAUNCHER_KIND_RUNTIME:
- case LAUNCHER_KIND_RUNNER:
- return a->runtime == b->runtime;
-
- case LAUNCHER_KIND_CONFIG:
- return a->config == b->config;
-
- case LAUNCHER_KIND_LAUNCHER:
- return FALSE;
-
- default:
- return FALSE;
- }
+ return g_object_new (IDE_TYPE_TERMINAL_LAUNCHER,
+ "context", self->context,
+ "run-command", self->run_command,
+ NULL);
}
diff --git a/src/libide/terminal/ide-terminal-launcher.h b/src/libide/terminal/ide-terminal-launcher.h
index 1e3b8ef6e..f6e66196d 100644
--- a/src/libide/terminal/ide-terminal-launcher.h
+++ b/src/libide/terminal/ide-terminal-launcher.h
@@ -20,7 +20,11 @@
#pragma once
-#include <libide-gui.h>
+#if !defined (IDE_TERMINAL_INSIDE) && !defined (IDE_TERMINAL_COMPILATION)
+# error "Only <libide-terminal.h> can be included directly."
+#endif
+
+#include <libide-foundry.h>
#include <libide-threading.h>
G_BEGIN_DECLS
@@ -31,48 +35,19 @@ IDE_AVAILABLE_IN_ALL
G_DECLARE_FINAL_TYPE (IdeTerminalLauncher, ide_terminal_launcher, IDE, TERMINAL_LAUNCHER, GObject)
IDE_AVAILABLE_IN_ALL
-IdeTerminalLauncher *ide_terminal_launcher_new (IdeContext *context);
-IDE_AVAILABLE_IN_ALL
-IdeTerminalLauncher *ide_terminal_launcher_new_for_launcher (IdeSubprocessLauncher *launcher);
-IDE_AVAILABLE_IN_ALL
-IdeTerminalLauncher *ide_terminal_launcher_new_for_config (IdeConfig *config);
-IDE_AVAILABLE_IN_ALL
-IdeTerminalLauncher *ide_terminal_launcher_new_for_debug (void);
-IDE_AVAILABLE_IN_ALL
-IdeTerminalLauncher *ide_terminal_launcher_new_for_runtime (IdeRuntime *runtime);
-IDE_AVAILABLE_IN_ALL
-IdeTerminalLauncher *ide_terminal_launcher_new_for_runner (IdeRuntime *runtime);
-IDE_AVAILABLE_IN_ALL
-gboolean ide_terminal_launcher_can_respawn (IdeTerminalLauncher *self);
-IDE_AVAILABLE_IN_ALL
-const gchar * const *ide_terminal_launcher_get_args (IdeTerminalLauncher *self);
-IDE_AVAILABLE_IN_ALL
-void ide_terminal_launcher_set_args (IdeTerminalLauncher *self,
- const gchar * const *args);
-IDE_AVAILABLE_IN_ALL
-const gchar *ide_terminal_launcher_get_cwd (IdeTerminalLauncher *self);
-IDE_AVAILABLE_IN_ALL
-void ide_terminal_launcher_set_cwd (IdeTerminalLauncher *self,
- const gchar *cwd);
-IDE_AVAILABLE_IN_ALL
-const gchar *ide_terminal_launcher_get_shell (IdeTerminalLauncher *self);
-IDE_AVAILABLE_IN_ALL
-void ide_terminal_launcher_set_shell (IdeTerminalLauncher *self,
- const gchar *shell);
-IDE_AVAILABLE_IN_ALL
-const gchar *ide_terminal_launcher_get_title (IdeTerminalLauncher *self);
+IdeTerminalLauncher *ide_terminal_launcher_new (IdeContext *context,
+ IdeRunCommand *run_command);
IDE_AVAILABLE_IN_ALL
-void ide_terminal_launcher_set_title (IdeTerminalLauncher *self,
- const gchar *title);
+IdeTerminalLauncher *ide_terminal_launcher_copy (IdeTerminalLauncher *self);
IDE_AVAILABLE_IN_ALL
-void ide_terminal_launcher_spawn_async (IdeTerminalLauncher *self,
- VtePty *pty,
- GCancellable *cancellable,
- GAsyncReadyCallback callback,
- gpointer user_data);
+void ide_terminal_launcher_spawn_async (IdeTerminalLauncher *self,
+ VtePty *pty,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
IDE_AVAILABLE_IN_ALL
-gboolean ide_terminal_launcher_spawn_finish (IdeTerminalLauncher *self,
- GAsyncResult *result,
- GError **error);
+gboolean ide_terminal_launcher_spawn_finish (IdeTerminalLauncher *self,
+ GAsyncResult *result,
+ GError **error);
G_END_DECLS
diff --git a/src/libide/terminal/ide-terminal-page.c b/src/libide/terminal/ide-terminal-page.c
index c7dd26485..b85039e65 100644
--- a/src/libide/terminal/ide-terminal-page.c
+++ b/src/libide/terminal/ide-terminal-page.c
@@ -37,6 +37,7 @@
#include "ide-terminal-page.h"
#include "ide-terminal-page-private.h"
#include "ide-terminal-page-actions.h"
+#include "ide-terminal-run-command-private.h"
#define FLAPPING_DURATION_USEC (G_USEC_PER_SEC / 20)
@@ -346,8 +347,14 @@ ide_terminal_page_context_set (GtkWidget *widget,
g_assert (IDE_IS_TERMINAL_PAGE (self));
g_assert (!context || IDE_IS_CONTEXT (context));
- if (self->launcher == NULL && context != NULL)
- self->launcher = ide_terminal_launcher_new (context);
+ if (context == NULL)
+ return;
+
+ if (self->launcher == NULL)
+ {
+ g_autoptr(IdeRunCommand) run_command = ide_terminal_run_command_new (IDE_TERMINAL_RUN_ON_HOST);
+ self->launcher = ide_terminal_launcher_new (context, run_command);
+ }
}
static GFile *
@@ -509,7 +516,7 @@ ide_terminal_page_class_init (IdeTerminalPageClass *klass)
"Launcher",
"The launcher to use for spawning",
IDE_TYPE_TERMINAL_LAUNCHER,
- (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+ (G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
g_object_class_install_properties (object_class, N_PROPS, properties);
}
@@ -543,6 +550,22 @@ ide_terminal_page_init (IdeTerminalPage *self)
ide_widget_set_context_handler (self, ide_terminal_page_context_set);
}
+/**
+ * ide_terminal_page_get_pty:
+ * @self: a #IdeTerminalPage
+ *
+ * Gets the #VtePty for the page.
+ *
+ * Returns: (transfer none): a #VtePty
+ */
+VtePty *
+ide_terminal_page_get_pty (IdeTerminalPage *self)
+{
+ g_return_val_if_fail (IDE_IS_TERMINAL_PAGE (self), NULL);
+
+ return self->pty;
+}
+
void
ide_terminal_page_set_pty (IdeTerminalPage *self,
VtePty *pty)
@@ -581,21 +604,8 @@ ide_terminal_page_set_launcher (IdeTerminalPage *self,
if (g_set_object (&self->launcher, launcher))
{
- gboolean can_split;
-
- if (launcher != NULL)
- {
- const gchar *title = ide_terminal_launcher_get_title (launcher);
- panel_widget_set_title (PANEL_WIDGET (self), title);
- can_split = ide_terminal_launcher_can_respawn (launcher);
- }
- else
- {
- self->manage_spawn = FALSE;
- can_split = FALSE;
- }
-
- ide_page_set_can_split (IDE_PAGE (self), can_split);
+ ide_page_set_can_split (IDE_PAGE (self), TRUE);
+ g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_LAUNCHER]);
}
}
diff --git a/src/libide/terminal/ide-terminal-page.h b/src/libide/terminal/ide-terminal-page.h
index 056bb6721..c6dc9d4ce 100644
--- a/src/libide/terminal/ide-terminal-page.h
+++ b/src/libide/terminal/ide-terminal-page.h
@@ -43,6 +43,8 @@ void ide_terminal_page_set_launcher (IdeTerminalPag
IDE_AVAILABLE_IN_ALL
IdeTerminalLauncher *ide_terminal_page_get_launcher (IdeTerminalPage *self);
IDE_AVAILABLE_IN_ALL
+VtePty *ide_terminal_page_get_pty (IdeTerminalPage *self);
+IDE_AVAILABLE_IN_ALL
void ide_terminal_page_set_pty (IdeTerminalPage *self,
VtePty *pty);
IDE_AVAILABLE_IN_ALL
diff --git a/src/libide/terminal/ide-terminal-private.h b/src/libide/terminal/ide-terminal-private.h
index 9eb7f1d05..d9015f5b6 100644
--- a/src/libide/terminal/ide-terminal-private.h
+++ b/src/libide/terminal/ide-terminal-private.h
@@ -22,12 +22,8 @@
#include <glib.h>
-#include "ide-terminal-launcher.h"
-
G_BEGIN_DECLS
-void _ide_terminal_init (void);
-gboolean _ide_terminal_launcher_are_similar (IdeTerminalLauncher *a,
- IdeTerminalLauncher *b);
+void _ide_terminal_init (void);
G_END_DECLS
diff --git a/src/libide/terminal/ide-terminal-run-command-private.h
b/src/libide/terminal/ide-terminal-run-command-private.h
new file mode 100644
index 000000000..0ae78f6b8
--- /dev/null
+++ b/src/libide/terminal/ide-terminal-run-command-private.h
@@ -0,0 +1,43 @@
+/* ide-terminal-run-command-private.h
+ *
+ * Copyright 2022 Christian Hergert <chergert redhat com>
+ *
+ * This program 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.
+ *
+ * This program 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/>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#pragma once
+
+#include <libide-foundry.h>
+
+G_BEGIN_DECLS
+
+#define IDE_TYPE_TERMINAL_RUN_COMMAND (ide_terminal_run_command_get_type())
+
+G_DECLARE_FINAL_TYPE (IdeTerminalRunCommand, ide_terminal_run_command, IDE, TERMINAL_RUN_COMMAND,
IdeRunCommand)
+
+typedef enum
+{
+ IDE_TERMINAL_RUN_ON_HOST,
+ IDE_TERMINAL_RUN_AS_SUBPROCESS,
+ IDE_TERMINAL_RUN_IN_PIPELINE,
+ IDE_TERMINAL_RUN_IN_RUNTIME,
+
+ IDE_TERMINAL_RUN_LAST
+} IdeTerminalRunLocality;
+
+IdeRunCommand *ide_terminal_run_command_new (IdeTerminalRunLocality locality);
+
+G_END_DECLS
diff --git a/src/libide/terminal/ide-terminal-run-command.c b/src/libide/terminal/ide-terminal-run-command.c
new file mode 100644
index 000000000..9f20bf3c2
--- /dev/null
+++ b/src/libide/terminal/ide-terminal-run-command.c
@@ -0,0 +1,142 @@
+/* ide-terminal-run-command.c
+ *
+ * Copyright 2022 Christian Hergert <chergert redhat com>
+ *
+ * This program 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.
+ *
+ * This program 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/>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#define G_LOG_DOMAIN "ide-terminal-run-command"
+
+#include "config.h"
+
+#include <libide-io.h>
+
+#include "ide-terminal-run-command-private.h"
+
+struct _IdeTerminalRunCommand
+{
+ IdeRunCommand parent_instance;
+ IdeTerminalRunLocality locality;
+};
+
+G_DEFINE_FINAL_TYPE (IdeTerminalRunCommand, ide_terminal_run_command, IDE_TYPE_RUN_COMMAND)
+
+static void
+ide_terminal_run_command_prepare_to_run (IdeRunCommand *run_command,
+ IdeRunContext *run_context,
+ IdeContext *context)
+{
+ IdeTerminalRunCommand *self = (IdeTerminalRunCommand *)run_command;
+ const char *user_shell;
+
+ IDE_ENTRY;
+
+ g_assert (IDE_IS_MAIN_THREAD ());
+ g_assert (IDE_IS_TERMINAL_RUN_COMMAND (self));
+ g_assert (IDE_IS_RUN_CONTEXT (run_context));
+ g_assert (IDE_IS_CONTEXT (context));
+
+ user_shell = ide_get_user_shell ();
+
+ switch (self->locality)
+ {
+ case IDE_TERMINAL_RUN_ON_HOST:
+ ide_run_context_push_host (run_context);
+ ide_run_context_append_argv (run_context, user_shell);
+ if (ide_shell_supports_dash_login (user_shell))
+ ide_run_context_append_argv (run_context, "--login");
+ break;
+
+ case IDE_TERMINAL_RUN_AS_SUBPROCESS:
+ if (g_find_program_in_path (user_shell))
+ {
+ ide_run_context_append_argv (run_context, user_shell);
+ if (ide_shell_supports_dash_login (user_shell))
+ ide_run_context_append_argv (run_context, "--login");
+ }
+ else
+ {
+ ide_run_context_append_argv (run_context, "/bin/sh");
+ ide_run_context_append_argv (run_context, "--login");
+ }
+ break;
+
+ case IDE_TERMINAL_RUN_IN_RUNTIME:
+ case IDE_TERMINAL_RUN_IN_PIPELINE:
+ {
+ IdeBuildManager *build_manager;
+ IdePipeline *pipeline;
+ IdeRuntime *runtime;
+
+ if (!ide_context_has_project (context) ||
+ !(build_manager = ide_build_manager_from_context (context)) ||
+ !(pipeline = ide_build_manager_get_pipeline (build_manager)) ||
+ !(runtime = ide_pipeline_get_runtime (pipeline)))
+ {
+ ide_run_context_push_error (run_context,
+ g_error_new (G_IO_ERROR,
+ G_IO_ERROR_NOT_INITIALIZED,
+ "Cannot spawn terminal without a pipeline"));
+ break;
+ }
+
+ if (!ide_runtime_contains_program_in_path (runtime, user_shell, NULL))
+ user_shell = "/bin/sh";
+
+ if (self->locality == IDE_TERMINAL_RUN_IN_PIPELINE)
+ ide_pipeline_prepare_run_context (pipeline, run_context);
+ else
+ ide_runtime_prepare_to_run (runtime, pipeline, run_context);
+
+ ide_run_context_append_argv (run_context, user_shell);
+ if (ide_shell_supports_dash_login (user_shell))
+ ide_run_context_append_argv (run_context, "--login");
+ }
+ break;
+
+ case IDE_TERMINAL_RUN_LAST:
+ default:
+ g_assert_not_reached ();
+ }
+
+ IDE_RUN_COMMAND_CLASS (ide_terminal_run_command_parent_class)->prepare_to_run (run_command, run_context,
context);
+
+ IDE_EXIT;
+}
+
+static void
+ide_terminal_run_command_class_init (IdeTerminalRunCommandClass *klass)
+{
+ IdeRunCommandClass *run_command_class = IDE_RUN_COMMAND_CLASS (klass);
+
+ run_command_class->prepare_to_run = ide_terminal_run_command_prepare_to_run;
+}
+
+static void
+ide_terminal_run_command_init (IdeTerminalRunCommand *self)
+{
+}
+
+IdeRunCommand *
+ide_terminal_run_command_new (IdeTerminalRunLocality locality)
+{
+ IdeTerminalRunCommand *self;
+
+ self = g_object_new (IDE_TYPE_TERMINAL_RUN_COMMAND, NULL);
+ self->locality = locality;
+
+ return IDE_RUN_COMMAND (self);
+}
diff --git a/src/libide/terminal/meson.build b/src/libide/terminal/meson.build
index eb69d8da3..1878d3ba7 100644
--- a/src/libide/terminal/meson.build
+++ b/src/libide/terminal/meson.build
@@ -30,6 +30,7 @@ libide_terminal_private_headers = [
'ide-terminal-page-actions.h',
'ide-terminal-page-private.h',
'ide-terminal-popover-row.h',
+ 'ide-terminal-run-command-private.h',
'ide-terminal-search-private.h',
'ide-terminal-private.h',
]
@@ -47,6 +48,7 @@ libide_terminal_private_sources = [
'ide-terminal-init.c',
'ide-terminal-page-actions.c',
'ide-terminal-popover-row.c',
+ 'ide-terminal-run-command.c',
]
#
diff --git a/src/plugins/shellcmd/gbp-shellcmd-run-command.c b/src/plugins/shellcmd/gbp-shellcmd-run-command.c
index 453a95327..3b8ea1e17 100644
--- a/src/plugins/shellcmd/gbp-shellcmd-run-command.c
+++ b/src/plugins/shellcmd/gbp-shellcmd-run-command.c
@@ -394,99 +394,6 @@ gbp_shellcmd_run_command_set_accelerator (GbpShellcmdRunCommand *self,
}
}
-IdeTerminalLauncher *
-gbp_shellcmd_run_command_create_launcher (GbpShellcmdRunCommand *self,
- IdeContext *context)
-{
- g_autoptr(IdeSubprocessLauncher) launcher = NULL;
- g_autoptr(IdeRunContext) run_context = NULL;
- g_autoptr(GError) error = NULL;
- g_autoptr(GFile) workdir = NULL;
- IdeBuildManager *build_manager = NULL;
- g_auto(GStrv) environ = NULL;
- IdePipeline *pipeline = NULL;
- const char * const *argv;
- const char * const *env;
- const char *builddir;
- const char *srcdir;
- const char *cwd;
-
- g_return_val_if_fail (GBP_IS_SHELLCMD_RUN_COMMAND (self), NULL);
- g_return_val_if_fail (IDE_IS_CONTEXT (context), NULL);
-
- workdir = ide_context_ref_workdir (context);
- srcdir = g_file_peek_path (workdir);
- builddir = g_file_peek_path (workdir);
-
- if (ide_context_has_project (context))
- {
- build_manager = ide_build_manager_from_context (context);
- pipeline = ide_build_manager_get_pipeline (build_manager);
- builddir = ide_pipeline_get_builddir (pipeline);
- srcdir = ide_pipeline_get_srcdir (pipeline);
- }
-
- environ = g_environ_setenv (environ, "BUILDDIR", builddir, TRUE);
- environ = g_environ_setenv (environ, "SRCDIR", srcdir, TRUE);
- environ = g_environ_setenv (environ, "USER", g_get_user_name (), TRUE);
- environ = g_environ_setenv (environ, "HOME", g_get_home_dir (), TRUE);
-
- run_context = ide_run_context_new ();
-
- switch (self->locality)
- {
- case GBP_SHELLCMD_LOCALITY_PIPELINE:
- if (pipeline == NULL ||
- !(launcher = ide_pipeline_create_launcher (pipeline, &error)))
- goto handle_error;
- ide_pipeline_prepare_run_context (pipeline, run_context);
- break;
-
- case GBP_SHELLCMD_LOCALITY_HOST:
- ide_run_context_push_host (run_context);
- break;
-
- case GBP_SHELLCMD_LOCALITY_SUBPROCESS:
- break;
-
- case GBP_SHELLCMD_LOCALITY_RUNNER: {
- IdeRuntime *runtime = ide_pipeline_get_runtime (pipeline);
- if (runtime == NULL)
- goto handle_error;
- ide_runtime_prepare_to_run (runtime, pipeline, run_context);
- break;
- }
-
- default:
- g_assert_not_reached ();
- }
-
- ide_run_context_push_expansion (run_context, (const char * const *)environ);
-
- if ((cwd = ide_run_command_get_cwd (IDE_RUN_COMMAND (self))))
- ide_run_context_set_cwd (run_context, cwd);
-
- if ((argv = ide_run_command_get_argv (IDE_RUN_COMMAND (self))))
- ide_run_context_append_args (run_context, argv);
-
- if ((env = ide_run_command_get_environ (IDE_RUN_COMMAND (self))))
- ide_run_context_add_environ (run_context, env);
-
- if (!(launcher = ide_run_context_end (run_context, &error)))
- goto handle_error;
-
- return ide_terminal_launcher_new_for_launcher (launcher);
-
-handle_error:
- if (error != NULL)
- ide_object_warning (context,
- "%s: %s",
- _("Failed to launch command"),
- error->message);
-
- return NULL;
-}
-
GbpShellcmdLocality
gbp_shellcmd_run_command_get_locality (GbpShellcmdRunCommand *self)
{
diff --git a/src/plugins/shellcmd/gbp-shellcmd-run-command.h b/src/plugins/shellcmd/gbp-shellcmd-run-command.h
index c25ac2e55..6b3ef0754 100644
--- a/src/plugins/shellcmd/gbp-shellcmd-run-command.h
+++ b/src/plugins/shellcmd/gbp-shellcmd-run-command.h
@@ -53,7 +53,5 @@ void gbp_shellcmd_run_command_set_accelerator (GbpShellcmdRunC
GbpShellcmdLocality gbp_shellcmd_run_command_get_locality (GbpShellcmdRunCommand *self);
void gbp_shellcmd_run_command_set_locality (GbpShellcmdRunCommand *self,
GbpShellcmdLocality locality);
-IdeTerminalLauncher *gbp_shellcmd_run_command_create_launcher (GbpShellcmdRunCommand *self,
- IdeContext *context);
G_END_DECLS
diff --git a/src/plugins/shellcmd/gbp-shellcmd-shortcut-provider.c
b/src/plugins/shellcmd/gbp-shellcmd-shortcut-provider.c
index a31e0a031..b96169602 100644
--- a/src/plugins/shellcmd/gbp-shellcmd-shortcut-provider.c
+++ b/src/plugins/shellcmd/gbp-shellcmd-shortcut-provider.c
@@ -43,7 +43,7 @@ gbp_shellcmd_shortcut_func (GtkWidget *widget,
GVariant *args,
gpointer user_data)
{
- GbpShellcmdRunCommand *command = user_data;
+ GbpShellcmdRunCommand *run_command = user_data;
g_autoptr(IdePanelPosition) position = NULL;
g_autoptr(IdeTerminalLauncher) launcher = NULL;
IdeWorkspace *workspace;
@@ -55,11 +55,11 @@ gbp_shellcmd_shortcut_func (GtkWidget *widget,
g_assert (GTK_IS_WIDGET (widget));
g_assert (args == NULL);
- g_assert (GBP_IS_SHELLCMD_RUN_COMMAND (command));
+ g_assert (GBP_IS_SHELLCMD_RUN_COMMAND (run_command));
g_debug ("Shortcut triggered to run command ā%sā which has accelerator %s",
- ide_run_command_get_display_name (IDE_RUN_COMMAND (command)),
- gbp_shellcmd_run_command_get_accelerator (command));
+ ide_run_command_get_display_name (IDE_RUN_COMMAND (run_command)),
+ gbp_shellcmd_run_command_get_accelerator (run_command));
if (!(workspace = ide_widget_get_workspace (widget)) ||
!(context = ide_workspace_get_context (workspace)))
@@ -69,10 +69,11 @@ gbp_shellcmd_shortcut_func (GtkWidget *widget,
!IDE_IS_EDITOR_WORKSPACE (workspace))
IDE_RETURN (FALSE);
- if (!(title = ide_run_command_get_display_name (IDE_RUN_COMMAND (command))))
+ if (!(title = ide_run_command_get_display_name (IDE_RUN_COMMAND (run_command))))
title = _("Untitled command");
- launcher = gbp_shellcmd_run_command_create_launcher (command, context);
+ launcher = ide_terminal_launcher_new (context, IDE_RUN_COMMAND (run_command));
+
page = g_object_new (IDE_TYPE_TERMINAL_PAGE,
"close-on-exit", FALSE,
"icon-name", "text-x-script-symbolic",
diff --git a/src/plugins/terminal/gbp-terminal-workspace-addin.c
b/src/plugins/terminal/gbp-terminal-workspace-addin.c
index 866faf3c1..e6a834ddd 100644
--- a/src/plugins/terminal/gbp-terminal-workspace-addin.c
+++ b/src/plugins/terminal/gbp-terminal-workspace-addin.c
@@ -28,234 +28,148 @@
#include <libide-terminal.h>
#include <libide-gui.h>
-#include "ide-terminal-private.h"
+#include "ide-terminal-run-command-private.h"
#include "gbp-terminal-workspace-addin.h"
struct _GbpTerminalWorkspaceAddin
{
- GObject parent_instance;
-
- IdeWorkspace *workspace;
-
- IdePane *bottom_dock;
- IdeTerminalPage *bottom;
-
- IdePane *run_panel;
- IdeTerminalPage *run_terminal;
+ GObject parent_instance;
+ IdeWorkspace *workspace;
};
-static IdeRuntime *
-find_runtime (IdeWorkspace *workspace)
-{
- IdeContext *context;
- IdeConfigManager *config_manager;
- IdeConfig *config;
-
- g_assert (IDE_IS_WORKSPACE (workspace));
-
- context = ide_workspace_get_context (workspace);
- config_manager = ide_config_manager_from_context (context);
- config = ide_config_manager_get_current (config_manager);
-
- return ide_config_get_runtime (config);
-}
-
-static gchar *
-find_builddir (IdeWorkspace *workspace)
-{
- IdeContext *context;
- IdeBuildManager *build_manager;
- IdePipeline *pipeline;
- const gchar *builddir = NULL;
-
- if ((context = ide_workspace_get_context (workspace)) &&
- (build_manager = ide_build_manager_from_context (context)) &&
- (pipeline = ide_build_manager_get_pipeline (build_manager)) &&
- (builddir = ide_pipeline_get_builddir (pipeline)) &&
- g_file_test (builddir, G_FILE_TEST_IS_DIR))
- return g_strdup (builddir);
-
- return NULL;
-}
+static void terminal_on_host_action (GbpTerminalWorkspaceAddin *self,
+ GVariant *param);
+static void terminal_as_subprocess_action (GbpTerminalWorkspaceAddin *self,
+ GVariant *param);
+static void terminal_in_pipeline_action (GbpTerminalWorkspaceAddin *self,
+ GVariant *param);
+static void terminal_in_runtime_action (GbpTerminalWorkspaceAddin *self,
+ GVariant *param);
+
+IDE_DEFINE_ACTION_GROUP (GbpTerminalWorkspaceAddin, gbp_terminal_workspace_addin, {
+ { "terminal-on-host", terminal_on_host_action, "s" },
+ { "terminal-as-subprocess", terminal_as_subprocess_action, "s" },
+ { "terminal-in-pipeline", terminal_in_pipeline_action, "s" },
+ { "terminal-in-runtime", terminal_in_runtime_action, "s" },
+})
static void
-new_terminal_activate (GSimpleAction *action,
- GVariant *param,
- gpointer user_data)
+gbp_terminal_workspace_addin_add_page (GbpTerminalWorkspaceAddin *self,
+ IdeTerminalRunLocality locality,
+ const char *cwd)
{
- GbpTerminalWorkspaceAddin *self = user_data;
g_autoptr(IdeTerminalLauncher) launcher = NULL;
g_autoptr(IdePanelPosition) position = NULL;
- g_autoptr(GFile) workdir = NULL;
- g_autofree gchar *cwd = NULL;
- IdePage *page;
- IdeRuntime *runtime = NULL;
+ g_autoptr(IdeRunCommand) run_command = NULL;
IdeContext *context;
- const gchar *name;
- GtkWidget *current_frame = NULL;
IdePage *current_page;
- const gchar *uri = NULL;
+ IdePage *page;
+
+ IDE_ENTRY;
g_assert (IDE_IS_MAIN_THREAD ());
- g_assert (G_IS_SIMPLE_ACTION (action));
g_assert (GBP_IS_TERMINAL_WORKSPACE_ADDIN (self));
+ g_assert (IDE_IS_WORKSPACE (self->workspace));
+ g_assert (locality >= IDE_TERMINAL_RUN_ON_HOST);
+ g_assert (locality < IDE_TERMINAL_RUN_LAST);
- /* If we are creating a new terminal while we already have a terminal
- * focused, then try to copy some details from that terminal.
- */
- if ((current_page = ide_workspace_get_most_recent_page (self->workspace)))
- current_frame = gtk_widget_get_ancestor (GTK_WIDGET (current_page), IDE_TYPE_FRAME);
+ run_command = ide_terminal_run_command_new (locality);
+
+ if (!ide_str_empty0 (cwd))
+ ide_run_command_set_cwd (run_command, cwd);
context = ide_workspace_get_context (self->workspace);
- workdir = ide_context_ref_workdir (context);
- name = g_action_get_name (G_ACTION (action));
+ launcher = ide_terminal_launcher_new (context, run_command);
- /* Only allow plain terminals unless this is a project */
- if (!ide_context_has_project (context) &&
- !ide_str_equal0 (name, "debug-terminal"))
- name = "new-terminal";
+ if ((current_page = ide_workspace_get_most_recent_page (self->workspace)))
+ position = ide_page_get_position (current_page);
- if (ide_str_equal0 (name, "new-terminal-in-config"))
- {
- IdeConfigManager *config_manager = ide_config_manager_from_context (context);
- IdeConfig *config = ide_config_manager_get_current (config_manager);
+ if (position == NULL)
+ position = ide_panel_position_new ();
- cwd = find_builddir (self->workspace);
- launcher = ide_terminal_launcher_new_for_config (config);
- }
- else if (ide_str_equal0 (name, "new-terminal-in-runtime"))
- {
- runtime = find_runtime (self->workspace);
- cwd = find_builddir (self->workspace);
- launcher = ide_terminal_launcher_new_for_runtime (runtime);
- }
- else if (ide_str_equal0 (name, "debug-terminal"))
- {
- launcher = ide_terminal_launcher_new_for_debug ();
- }
- else if (ide_str_equal0 (name, "new-terminal-in-runner"))
- {
- runtime = find_runtime (self->workspace);
- launcher = ide_terminal_launcher_new_for_runner (runtime);
- }
- else if (ide_str_equal0 (name, "new-terminal-in-dir"))
- {
- page = ide_workspace_get_most_recent_page (self->workspace);
+ page = g_object_new (IDE_TYPE_TERMINAL_PAGE,
+ "respawn-on-exit", FALSE,
+ "manage-spawn", TRUE,
+ "launcher", launcher,
+ "visible", TRUE,
+ NULL);
+ ide_workspace_add_page (self->workspace, page, position);
+ panel_widget_raise (PANEL_WIDGET (page));
+ gtk_widget_grab_focus (GTK_WIDGET (page));
- if (IDE_IS_EDITOR_PAGE (page))
- {
- IdeBuffer *buffer = ide_editor_page_get_buffer (IDE_EDITOR_PAGE (page));
+ IDE_EXIT;
+}
- if (buffer != NULL)
- {
- GFile *file = ide_buffer_get_file (buffer);
- g_autoptr(GFile) parent = g_file_get_parent (file);
+static void
+terminal_on_host_action (GbpTerminalWorkspaceAddin *self,
+ GVariant *param)
+{
+ const char *cwd = g_variant_get_string (param, NULL);
+ g_autofree char *project_dir = NULL;
- cwd = g_file_get_path (parent);
- }
- }
- }
- else
+ if (ide_str_empty0 (cwd))
{
- launcher = ide_terminal_launcher_new (context);
- cwd = g_file_get_path (workdir);
+ IdeContext *context = ide_workspace_get_context (self->workspace);
+ g_autoptr(GFile) workdir = ide_context_ref_workdir (context);
+ cwd = project_dir = g_file_get_path (workdir);
}
- if (IDE_IS_TERMINAL_PAGE (current_page))
- {
- if (_ide_terminal_launcher_are_similar (launcher,
- ide_terminal_page_get_launcher (IDE_TERMINAL_PAGE
(current_page))))
- uri = ide_terminal_page_get_current_directory_uri (IDE_TERMINAL_PAGE (current_page));
- }
+ gbp_terminal_workspace_addin_add_page (self, IDE_TERMINAL_RUN_ON_HOST, cwd);
+}
- if (uri != NULL)
- {
- g_autoptr(GFile) file = g_file_new_for_uri (uri);
+static void
+terminal_as_subprocess_action (GbpTerminalWorkspaceAddin *self,
+ GVariant *param)
+{
+ const char *cwd = g_variant_get_string (param, NULL);
- if (g_file_is_native (file))
- ide_terminal_launcher_set_cwd (launcher, g_file_peek_path (file));
- else if (cwd != NULL)
- ide_terminal_launcher_set_cwd (launcher, cwd);
- }
- else if (cwd != NULL)
- {
- ide_terminal_launcher_set_cwd (launcher, cwd);
- }
+ if (ide_str_empty0 (cwd))
+ cwd = g_get_home_dir ();
- page = g_object_new (IDE_TYPE_TERMINAL_PAGE,
- "launcher", launcher,
- "respawn-on-exit", FALSE,
- "visible", TRUE,
- NULL);
+ gbp_terminal_workspace_addin_add_page (self, IDE_TERMINAL_RUN_AS_SUBPROCESS, cwd);
+}
- if (current_frame != NULL)
- position = ide_frame_get_position (IDE_FRAME (current_frame));
- else
- position = ide_panel_position_new ();
+static void
+terminal_in_pipeline_action (GbpTerminalWorkspaceAddin *self,
+ GVariant *param)
+{
+ gbp_terminal_workspace_addin_add_page (self,
+ IDE_TERMINAL_RUN_IN_PIPELINE,
+ g_variant_get_string (param, NULL));
+}
- ide_workspace_add_page (self->workspace, page, position);
- panel_widget_raise (PANEL_WIDGET (page));
- gtk_widget_grab_focus (GTK_WIDGET (page));
+static void
+terminal_in_runtime_action (GbpTerminalWorkspaceAddin *self,
+ GVariant *param)
+{
+ const char *cwd = g_variant_get_string (param, NULL);
+
+ if (ide_str_empty0 (cwd))
+ cwd = g_get_home_dir ();
+
+ gbp_terminal_workspace_addin_add_page (self, IDE_TERMINAL_RUN_AS_SUBPROCESS, cwd);
+ gbp_terminal_workspace_addin_add_page (self, IDE_TERMINAL_RUN_IN_RUNTIME, cwd);
}
static void
-on_run_manager_run (GbpTerminalWorkspaceAddin *self,
- IdeRunContext *run_context,
- IdeRunManager *run_manager)
+on_run_manager_run (IdeRunManager *run_manager,
+ IdeRunContext *run_context,
+ IdeTerminalPage *page)
{
g_autoptr(GDateTime) now = NULL;
g_autofree char *formatted = NULL;
g_autofree char *tmp = NULL;
- VtePty *pty = NULL;
+ VtePty *pty;
IDE_ENTRY;
- g_assert (GBP_IS_TERMINAL_WORKSPACE_ADDIN (self));
+ g_assert (IDE_IS_MAIN_THREAD ());
g_assert (IDE_IS_RUN_CONTEXT (run_context));
g_assert (IDE_IS_RUN_MANAGER (run_manager));
+ g_assert (IDE_IS_TERMINAL_PAGE (page));
- /*
- * We need to create a new or re-use our existing terminal page
- * for run output. Additionally, we need to override the stdin,
- * stdout, and stderr file-descriptors to our pty master for the
- * terminal instance.
- */
-
- if (!(pty = vte_pty_new_sync (VTE_PTY_DEFAULT, NULL, NULL)))
- {
- g_warning ("Failed to allocate PTY for run output");
- IDE_GOTO (failure);
- }
-
- if (self->run_terminal == NULL)
- {
- g_autoptr(IdePanelPosition) position = NULL;
-
- self->run_terminal = g_object_new (IDE_TYPE_TERMINAL_PAGE,
- "manage-spawn", FALSE,
- "pty", pty,
- NULL);
- ide_pane_observe (g_object_new (IDE_TYPE_PANE,
- "child", self->run_terminal,
- "vexpand", TRUE,
- "hexpand", TRUE,
- "icon-name", "builder-run-start-symbolic",
- "title", _("Application Output"),
- NULL),
- &self->run_panel);
-
- position = ide_panel_position_new ();
- ide_panel_position_set_edge (position, PANEL_DOCK_POSITION_BOTTOM);
- ide_workspace_add_pane (self->workspace, self->run_panel, position);
- }
- else
- {
- ide_terminal_page_set_pty (self->run_terminal, pty);
- }
-
- if (self->run_panel != NULL)
- panel_widget_raise (PANEL_WIDGET (self->run_panel));
+ pty = ide_terminal_page_get_pty (page);
ide_run_context_push (run_context, NULL, NULL, NULL);
ide_run_context_set_pty (run_context, pty);
@@ -267,43 +181,37 @@ on_run_manager_run (GbpTerminalWorkspaceAddin *self,
/* translators: %s is replaced with the current local time of day */
formatted = g_strdup_printf (_("Application started at %s\r\n"), tmp);
- ide_terminal_page_feed (self->run_terminal, formatted);
+ ide_terminal_page_feed (page, formatted);
-failure:
- g_clear_object (&pty);
+ panel_widget_raise (PANEL_WIDGET (page));
IDE_EXIT;
}
static void
-on_run_manager_stopped (GbpTerminalWorkspaceAddin *self,
- IdeRunManager *run_manager)
+on_run_manager_stopped (IdeRunManager *run_manager,
+ IdeTerminalPage *page)
{
+ IDE_ENTRY;
+
g_assert (IDE_IS_MAIN_THREAD ());
- g_assert (GBP_IS_TERMINAL_WORKSPACE_ADDIN (self));
g_assert (IDE_IS_RUN_MANAGER (run_manager));
+ g_assert (IDE_IS_TERMINAL_PAGE (page));
- ide_terminal_page_feed (self->run_terminal, _("Application exited\r\n"));
-}
+ ide_terminal_page_feed (page, _("Application exited"));
+ ide_terminal_page_feed (page, "\r\n");
-static const GActionEntry terminal_actions[] = {
- { "new-terminal", new_terminal_activate },
- { "new-terminal-in-config", new_terminal_activate },
- { "new-terminal-in-runner", new_terminal_activate },
- { "new-terminal-in-runtime", new_terminal_activate },
- { "new-terminal-in-dir", new_terminal_activate },
- { "debug-terminal", new_terminal_activate },
-};
+ IDE_EXIT;
+}
static void
gbp_terminal_workspace_addin_load (IdeWorkspaceAddin *addin,
IdeWorkspace *workspace)
{
GbpTerminalWorkspaceAddin *self = (GbpTerminalWorkspaceAddin *)addin;
- IdeWorkbench *workbench;
g_autoptr(IdePanelPosition) position = NULL;
- IdeRunManager *run_manager;
- IdeContext *context;
+ IdePage *page;
+ IdePane *pane;
g_assert (GBP_IS_TERMINAL_WORKSPACE_ADDIN (self));
g_assert (IDE_IS_PRIMARY_WORKSPACE (workspace) ||
@@ -311,45 +219,54 @@ gbp_terminal_workspace_addin_load (IdeWorkspaceAddin *addin,
self->workspace = workspace;
- g_action_map_add_action_entries (G_ACTION_MAP (workspace),
- terminal_actions,
- G_N_ELEMENTS (terminal_actions),
- self);
-
+ gtk_widget_insert_action_group (GTK_WIDGET (workspace),
+ "terminal",
+ G_ACTION_GROUP (self));
+ /* Always add the terminal panel to primary/editor workspaces */
position = ide_panel_position_new ();
ide_panel_position_set_edge (position, PANEL_DOCK_POSITION_BOTTOM);
+ page = g_object_new (IDE_TYPE_TERMINAL_PAGE,
+ "respawn-on-exit", TRUE,
+ "visible", TRUE,
+ NULL);
+ pane = g_object_new (IDE_TYPE_PANE,
+ "title", _("Terminal"),
+ "icon-name", "builder-terminal-symbolic",
+ "child", page,
+ NULL);
+ ide_workspace_add_pane (workspace, pane, position);
- self->bottom = g_object_new (IDE_TYPE_TERMINAL_PAGE,
- "respawn-on-exit", TRUE,
- "visible", TRUE,
- NULL);
- ide_pane_observe (g_object_new (IDE_TYPE_PANE,
- "title", _("Terminal"),
- "icon-name", "builder-terminal-symbolic",
- "child", self->bottom,
- NULL),
- &self->bottom_dock);
-
- ide_workspace_add_pane (workspace, IDE_PANE (self->bottom_dock), position);
-
- workbench = ide_widget_get_workbench (GTK_WIDGET (workspace));
-
- if (ide_workbench_has_project (workbench) && IDE_IS_PRIMARY_WORKSPACE (workspace))
+ /* Setup panel for application output */
+ if (IDE_IS_PRIMARY_WORKSPACE (workspace))
{
- /* Setup terminals when a project is run */
- context = ide_widget_get_context (GTK_WIDGET (workspace));
- run_manager = ide_run_manager_from_context (context);
+ IdeWorkbench *workbench = ide_workspace_get_workbench (workspace);
+ IdeContext *context = ide_workbench_get_context (workbench);
+ IdeRunManager *run_manager = ide_run_manager_from_context (context);
+ VtePty *pty = vte_pty_new_sync (VTE_PTY_DEFAULT, NULL, NULL);
+
+ page = g_object_new (IDE_TYPE_TERMINAL_PAGE,
+ "respawn-on-exit", FALSE,
+ "manage-spawn", FALSE,
+ "pty", pty,
+ NULL);
+ pane = g_object_new (IDE_TYPE_PANE,
+ "title", _("Application Output"),
+ "icon-name", "builder-run-start-symbolic",
+ "child", page,
+ NULL);
+ ide_workspace_add_pane (workspace, pane, position);
+
g_signal_connect_object (run_manager,
"run",
G_CALLBACK (on_run_manager_run),
- self,
- G_CONNECT_SWAPPED);
+ page,
+ 0);
g_signal_connect_object (run_manager,
"stopped",
G_CALLBACK (on_run_manager_stopped),
- self,
- G_CONNECT_SWAPPED);
+ page,
+ 0);
}
}
@@ -369,11 +286,9 @@ gbp_terminal_workspace_addin_unload (IdeWorkspaceAddin *addin,
if (ide_workbench_has_project (workbench))
{
- IdeRunManager *run_manager;
- IdeContext *context;
+ IdeContext *context = ide_widget_get_context (GTK_WIDGET (workspace));
+ IdeRunManager *run_manager = ide_run_manager_from_context (context);
- context = ide_widget_get_context (GTK_WIDGET (workspace));
- run_manager = ide_run_manager_from_context (context);
g_signal_handlers_disconnect_by_func (run_manager,
G_CALLBACK (on_run_manager_run),
self);
@@ -382,16 +297,7 @@ gbp_terminal_workspace_addin_unload (IdeWorkspaceAddin *addin,
self);
}
- for (guint i = 0; i < G_N_ELEMENTS (terminal_actions); i++)
- g_action_map_remove_action (G_ACTION_MAP (workspace), terminal_actions[i].name);
-
- ide_clear_pane (&self->bottom_dock);
- ide_clear_pane (&self->run_panel);
-
- self->bottom = NULL;
- self->bottom_dock = NULL;
- self->run_terminal = NULL;
- self->run_panel = NULL;
+ gtk_widget_insert_action_group (GTK_WIDGET (workspace), "terminal", NULL);
self->workspace = NULL;
}
@@ -404,6 +310,7 @@ workspace_addin_iface_init (IdeWorkspaceAddinInterface *iface)
}
G_DEFINE_FINAL_TYPE_WITH_CODE (GbpTerminalWorkspaceAddin, gbp_terminal_workspace_addin, G_TYPE_OBJECT,
+ G_IMPLEMENT_INTERFACE (G_TYPE_ACTION_GROUP,
gbp_terminal_workspace_addin_init_action_group)
G_IMPLEMENT_INTERFACE (IDE_TYPE_WORKSPACE_ADDIN, workspace_addin_iface_init))
static void
diff --git a/src/plugins/terminal/gtk/keybindings.json b/src/plugins/terminal/gtk/keybindings.json
index cfa21b1a4..271ccd108 100644
--- a/src/plugins/terminal/gtk/keybindings.json
+++ b/src/plugins/terminal/gtk/keybindings.json
@@ -1,7 +1,7 @@
/* New Terminal Actions */
-{ "trigger" : "<Control><Shift>t", "action" : "win.new-terminal", "when" : "canEdit()", "phase" : "capture"
},
-{ "trigger" : "<Control><Alt><Shift>t", "action" : "win.new-terminal-in-config", "when" : "canEdit()",
"phase" : "capture" },
-{ "trigger" : "<Control><Alt>t", "action" : "win.new-terminal-in-runner", "when" : "canEdit()", "phase" :
"capture" },
+{ "trigger" : "<Control><Shift>t", "action" : "terminal.terminal-on-host", "args" : "''", "when" :
"canEdit()", "phase" : "capture" },
+{ "trigger" : "<Control><Alt><Shift>t", "action" : "terminal.terminal-in-pipeline", "args" : "''", "when" :
"canEdit()", "phase" : "capture" },
+{ "trigger" : "<Control><Alt>t", "action" : "terminal.terminal-in-runtime", "args" : "''", "when" :
"canEdit()", "phase" : "capture" },
/* IdeTerminal */
{ "trigger" : "<Control><Shift>c", "action" : "clipboard.copy", "when" : "inTerminal()", "phase" : "capture"
},
diff --git a/src/plugins/terminal/gtk/menus.ui b/src/plugins/terminal/gtk/menus.ui
index 75480c185..e2faa4933 100644
--- a/src/plugins/terminal/gtk/menus.ui
+++ b/src/plugins/terminal/gtk/menus.ui
@@ -3,25 +3,21 @@
<menu id="new-document-menu">
<section id="new-terminal-section">
<item>
- <attribute name="id">new-terminal</attribute>
- <attribute name="after">new-file</attribute>
- <attribute name="before">new-documentation-page</attribute>
<attribute name="label" translatable="yes">New _Terminal</attribute>
- <attribute name="action">win.new-terminal</attribute>
+ <attribute name="action">terminal.terminal-on-host</attribute>
+ <attribute name="target" type="s">''</attribute>
<attribute name="accel"><ctrl><shift>t</attribute>
</item>
<item>
- <attribute name="id">new-build-terminal</attribute>
- <attribute name="after">new-terminal</attribute>
<attribute name="label" translatable="yes">New _Build Terminal</attribute>
- <attribute name="action">win.new-terminal-in-config</attribute>
+ <attribute name="action">terminal.terminal-in-pipeline</attribute>
+ <attribute name="target" type="s">''</attribute>
<attribute name="accel"><ctrl><shift><alt>t</attribute>
</item>
<item>
- <attribute name="id">new-run-terminal</attribute>
- <attribute name="after">new-build-terminal</attribute>
<attribute name="label" translatable="yes">New _Runtime Terminal</attribute>
- <attribute name="action">win.new-terminal-in-runner</attribute>
+ <attribute name="action">terminal.terminal-in-runtime</attribute>
+ <attribute name="target" type="s">''</attribute>
<attribute name="accel"><ctrl><alt>t</attribute>
</item>
</section>
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]