[gnome-builder] terminal: add Run Output panel when running project
- From: Christian Hergert <chergert src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-builder] terminal: add Run Output panel when running project
- Date: Sat, 12 Nov 2016 05:31:59 +0000 (UTC)
commit 68d434956e2cf2a2b5745177f63bfb968dd5f915
Author: Christian Hergert <chergert redhat com>
Date: Fri Nov 11 21:31:27 2016 -0800
terminal: add Run Output panel when running project
This repurposes GbTerminalView for yet another view which shows the output
from running the project. It creates a PTY slave and assigns it to the
runner when IdeRunManager::run(IdeRunner) is emitted.
plugins/terminal/Makefile.am | 2 +
plugins/terminal/gb-terminal-util.c | 59 +++++++++++++
plugins/terminal/gb-terminal-util.h | 30 +++++++
plugins/terminal/gb-terminal-view-private.h | 4 +-
plugins/terminal/gb-terminal-view.c | 102 +++++++++++++++++------
plugins/terminal/gb-terminal-view.h | 4 +
plugins/terminal/gb-terminal-workbench-addin.c | 108 +++++++++++++++++++++++-
7 files changed, 282 insertions(+), 27 deletions(-)
---
diff --git a/plugins/terminal/Makefile.am b/plugins/terminal/Makefile.am
index 6a33d76..17c2f13 100644
--- a/plugins/terminal/Makefile.am
+++ b/plugins/terminal/Makefile.am
@@ -16,6 +16,8 @@ libterminal_la_SOURCES = \
gb-terminal-application-addin.h \
gb-terminal-plugin.c \
gb-terminal-private.h \
+ gb-terminal-util.c \
+ gb-terminal-util.h \
gb-terminal-view.c \
gb-terminal-view.h \
gb-terminal-view-private.h \
diff --git a/plugins/terminal/gb-terminal-util.c b/plugins/terminal/gb-terminal-util.c
new file mode 100644
index 0000000..303a897
--- /dev/null
+++ b/plugins/terminal/gb-terminal-util.c
@@ -0,0 +1,59 @@
+/* gb-terminal-util.c
+ *
+ * Copyright (C) 2016 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/>.
+ */
+
+#define G_LOG_DOMAIN "gb-terminal-util"
+
+#include "config.h"
+
+#include <fcntl.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "gb-terminal-util.h"
+
+gint
+gb_vte_pty_create_slave (VtePty *pty)
+{
+ gint master_fd;
+#ifdef HAVE_PTSNAME_R
+ char name[PATH_MAX + 1];
+#else
+ const char *name;
+#endif
+
+ g_assert (VTE_IS_PTY (pty));
+
+ if (-1 == (master_fd = vte_pty_get_fd (pty)))
+ return -1;
+
+ if (grantpt (master_fd) != 0)
+ return -1;
+
+ if (unlockpt (master_fd) != 0)
+ return -1;
+
+#ifdef HAVE_PTSNAME_R
+ if (ptsname_r (master_fd, name, sizeof name - 1) != 0)
+ return -1;
+#else
+ if (NULL == (name = ptsname (master_fd)))
+ return -1;
+#endif
+
+ return open (name, O_RDWR | O_CLOEXEC);
+}
diff --git a/plugins/terminal/gb-terminal-util.h b/plugins/terminal/gb-terminal-util.h
new file mode 100644
index 0000000..e0fb774
--- /dev/null
+++ b/plugins/terminal/gb-terminal-util.h
@@ -0,0 +1,30 @@
+/* gb-terminal-util.h
+ *
+ * Copyright (C) 2016 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/>.
+ */
+
+#ifndef GB_TERMINAL_UTIL_H
+#define GB_TERMINAL_UTIL_H
+
+#include <vte/vte.h>
+
+G_BEGIN_DECLS
+
+int gb_vte_pty_create_slave (VtePty *pty);
+
+G_END_DECLS
+
+#endif /* GB_TERMINAL_UTIL_H */
diff --git a/plugins/terminal/gb-terminal-view-private.h b/plugins/terminal/gb-terminal-view-private.h
index 7d271e9..775ebdc 100644
--- a/plugins/terminal/gb-terminal-view-private.h
+++ b/plugins/terminal/gb-terminal-view-private.h
@@ -41,12 +41,14 @@ struct _GbTerminalView
GtkWidget *bottom_container;
+ VtePty *pty;
+
gint64 last_respawn;
+ guint manage_spawn : 1;
guint top_has_spawned : 1;
guint bottom_has_spawned : 1;
guint bottom_has_focus : 1;
-
guint top_has_needs_attention : 1;
guint bottom_has_needs_attention : 1;
};
diff --git a/plugins/terminal/gb-terminal-view.c b/plugins/terminal/gb-terminal-view.c
index d7979e8..42ceb64 100644
--- a/plugins/terminal/gb-terminal-view.c
+++ b/plugins/terminal/gb-terminal-view.c
@@ -28,6 +28,7 @@
#include <unistd.h>
#include "gb-terminal.h"
+#include "gb-terminal-util.h"
#include "gb-terminal-view.h"
#include "gb-terminal-view-private.h"
#include "gb-terminal-view-actions.h"
@@ -37,6 +38,8 @@ G_DEFINE_TYPE (GbTerminalView, gb_terminal_view, IDE_TYPE_LAYOUT_VIEW)
enum {
PROP_0,
PROP_FONT_NAME,
+ PROP_MANAGE_SPAWN,
+ PROP_PTY,
LAST_PROP
};
@@ -191,15 +194,9 @@ gb_terminal_respawn (GbTerminalView *self,
VtePty *pty = NULL;
GFile *workdir;
gint64 now;
- int master_fd = -1;
int tty_fd = -1;
gint stdout_fd = -1;
gint stderr_fd = -1;
-#ifdef HAVE_PTSNAME_R
- char name[PATH_MAX + 1];
-#else
- const char *name;
-#endif
IDE_ENTRY;
@@ -250,24 +247,7 @@ gb_terminal_respawn (GbTerminalView *self,
vte_terminal_set_pty (terminal, pty);
- if (-1 == (master_fd = vte_pty_get_fd (pty)))
- IDE_GOTO (failure);
-
- if (grantpt (master_fd) != 0)
- IDE_GOTO (failure);
-
- if (unlockpt (master_fd) != 0)
- IDE_GOTO (failure);
-
-#ifdef HAVE_PTSNAME_R
- if (ptsname_r (master_fd, name, sizeof name - 1) != 0)
- IDE_GOTO (failure);
-#else
- if (NULL == (name = ptsname (master_fd)))
- IDE_GOTO (failure);
-#endif
-
- if (-1 == (tty_fd = open (name, O_RDWR | O_CLOEXEC)))
+ if (-1 == (tty_fd = gb_vte_pty_create_slave (pty)))
IDE_GOTO (failure);
/* dup() is safe as it will inherit O_CLOEXEC */
@@ -326,11 +306,14 @@ gb_terminal_realize (GtkWidget *widget)
GTK_WIDGET_CLASS (gb_terminal_view_parent_class)->realize (widget);
- if (!self->top_has_spawned)
+ if (self->manage_spawn && !self->top_has_spawned)
{
self->top_has_spawned = TRUE;
gb_terminal_respawn (self, self->terminal_top);
}
+
+ if (!self->manage_spawn && self->pty != NULL)
+ vte_terminal_set_pty (self->terminal_top, self->pty);
}
static void
@@ -691,11 +674,35 @@ gb_terminal_view_finalize (GObject *object)
g_clear_object (&self->save_as_file_top);
g_clear_object (&self->save_as_file_bottom);
g_clear_pointer (&self->selection_buffer, g_free);
+ g_clear_object (&self->pty);
G_OBJECT_CLASS (gb_terminal_view_parent_class)->finalize (object);
}
static void
+gb_terminal_view_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GbTerminalView *self = GB_TERMINAL_VIEW (object);
+
+ switch (prop_id)
+ {
+ case PROP_MANAGE_SPAWN:
+ g_value_set_boolean (value, self->manage_spawn);
+ break;
+
+ case PROP_PTY:
+ g_value_set_object (value, self->pty);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
gb_terminal_view_set_property (GObject *object,
guint prop_id,
const GValue *value,
@@ -709,6 +716,14 @@ gb_terminal_view_set_property (GObject *object,
gb_terminal_view_set_font_name (self, g_value_get_string (value));
break;
+ case PROP_MANAGE_SPAWN:
+ self->manage_spawn = g_value_get_boolean (value);
+ break;
+
+ case PROP_PTY:
+ self->pty = g_value_dup_object (value);
+ break;
+
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
@@ -722,6 +737,7 @@ gb_terminal_view_class_init (GbTerminalViewClass *klass)
IdeLayoutViewClass *view_class = IDE_LAYOUT_VIEW_CLASS (klass);
object_class->finalize = gb_terminal_view_finalize;
+ object_class->get_property = gb_terminal_view_get_property;
object_class->set_property = gb_terminal_view_set_property;
widget_class->realize = gb_terminal_realize;
@@ -748,6 +764,20 @@ gb_terminal_view_class_init (GbTerminalViewClass *klass)
NULL,
(G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS));
+ properties [PROP_MANAGE_SPAWN] =
+ g_param_spec_boolean ("manage-spawn",
+ "Manage Spawn",
+ "Manage Spawn",
+ TRUE,
+ (G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
+
+ properties [PROP_PTY] =
+ g_param_spec_object ("pty",
+ "Pty",
+ "The psuedo terminal to use",
+ VTE_TYPE_PTY,
+ (G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
+
g_object_class_install_properties (object_class, LAST_PROP, properties);
g_type_ensure (GB_TYPE_TERMINAL);
@@ -759,6 +789,8 @@ gb_terminal_view_init (GbTerminalView *self)
GtkStyleContext *style_context;
g_autoptr(GSettings) settings = NULL;
+ self->manage_spawn = TRUE;
+
gtk_widget_init_template (GTK_WIDGET (self));
gb_terminal_view_connect_terminal (self, self->terminal_top);
@@ -778,3 +810,23 @@ gb_terminal_view_init (GbTerminalView *self)
gtk_widget_set_can_focus (GTK_WIDGET (self->terminal_top), TRUE);
}
+
+void
+gb_terminal_view_set_pty (GbTerminalView *self,
+ VtePty *pty)
+{
+ g_return_if_fail (GB_IS_TERMINAL_VIEW (self));
+ g_return_if_fail (VTE_IS_PTY (pty));
+
+ if (self->manage_spawn)
+ {
+ g_warning ("Cannot set pty when GbTerminalView manages tty");
+ return;
+ }
+
+ if (self->terminal_top)
+ {
+ vte_terminal_reset (self->terminal_top, TRUE, TRUE);
+ vte_terminal_set_pty (self->terminal_top, pty);
+ }
+}
diff --git a/plugins/terminal/gb-terminal-view.h b/plugins/terminal/gb-terminal-view.h
index 5b8e7a3..b4169da 100644
--- a/plugins/terminal/gb-terminal-view.h
+++ b/plugins/terminal/gb-terminal-view.h
@@ -20,6 +20,7 @@
#define GB_TERMINAL_VIEW_H
#include <ide.h>
+#include <vte/vte.h>
G_BEGIN_DECLS
@@ -27,6 +28,9 @@ G_BEGIN_DECLS
G_DECLARE_FINAL_TYPE (GbTerminalView, gb_terminal_view, GB, TERMINAL_VIEW, IdeLayoutView)
+void gb_terminal_view_set_pty (GbTerminalView *self,
+ VtePty *pty);
+
G_END_DECLS
#endif /* GB_TERMINAL_VIEW_H */
diff --git a/plugins/terminal/gb-terminal-workbench-addin.c b/plugins/terminal/gb-terminal-workbench-addin.c
index 8b0a412..c970857 100644
--- a/plugins/terminal/gb-terminal-workbench-addin.c
+++ b/plugins/terminal/gb-terminal-workbench-addin.c
@@ -16,9 +16,15 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+#define G_LOG_DOMAIN "gb-terminal-workbench-addin"
+
+#include "config.h"
+
#include <glib/gi18n.h>
#include <ide.h>
+#include <vte/vte.h>
+#include "gb-terminal-util.h"
#include "gb-terminal-view.h"
#include "gb-terminal-workbench-addin.h"
@@ -30,6 +36,9 @@ struct _GbTerminalWorkbenchAddin
GbTerminalView *panel_terminal;
GtkWidget *panel_dock_widget;
+
+ GbTerminalView *run_terminal;
+ GtkWidget *run_panel;
};
static void workbench_addin_iface_init (IdeWorkbenchAddinInterface *iface);
@@ -62,17 +71,101 @@ new_terminal_activate_cb (GSimpleAction *action,
}
static void
+on_run_manager_run (GbTerminalWorkbenchAddin *self,
+ IdeRunner *runner,
+ IdeRunManager *run_manager)
+{
+ IdeEnvironment *env;
+ VtePty *pty = NULL;
+ int tty_fd;
+
+ IDE_ENTRY;
+
+ g_assert (GB_IS_TERMINAL_WORKBENCH_ADDIN (self));
+ g_assert (IDE_IS_RUNNER (runner));
+ g_assert (IDE_IS_RUN_MANAGER (run_manager));
+
+ /*
+ * We need to create a new or re-use our existing terminal view
+ * for run output. Additionally, we need to override the stdin,
+ * stdout, and stderr file-descriptors to our pty master for the
+ * terminal instance.
+ */
+
+ pty = vte_pty_new_sync (VTE_PTY_DEFAULT, NULL, NULL);
+
+ if (pty == NULL)
+ {
+ g_warning ("Failed to allocate PTY for run output");
+ IDE_GOTO (failure);
+ }
+
+ if (self->run_terminal == NULL)
+ {
+ IdePerspective *perspective;
+ GbTerminalView *view;
+ GtkWidget *bottom_pane;
+ GtkWidget *panel;
+
+ view = g_object_new (GB_TYPE_TERMINAL_VIEW,
+ "manage-spawn", FALSE,
+ "pty", pty,
+ "visible", TRUE,
+ NULL);
+ ide_set_weak_pointer (&self->run_terminal, view);
+
+ panel = g_object_new (PNL_TYPE_DOCK_WIDGET,
+ "child", self->run_terminal,
+ "expand", TRUE,
+ "title", _("Run Output"),
+ "visible", TRUE,
+ NULL);
+ ide_set_weak_pointer (&self->run_panel, panel);
+
+ perspective = ide_workbench_get_perspective_by_name (self->workbench, "editor");
+ g_assert (IDE_IS_LAYOUT (perspective));
+
+ bottom_pane = pnl_dock_bin_get_bottom_edge (PNL_DOCK_BIN (perspective));
+ gtk_container_add (GTK_CONTAINER (bottom_pane), GTK_WIDGET (self->run_panel));
+ }
+ else
+ {
+ gb_terminal_view_set_pty (self->run_terminal, pty);
+ }
+
+ if (-1 != (tty_fd = gb_vte_pty_create_slave (pty)))
+ {
+ ide_runner_set_tty (runner, tty_fd);
+ close (tty_fd);
+ }
+
+ env = ide_runner_get_environment (runner);
+ ide_environment_setenv (env, "TERM", "xterm-256color");
+ ide_environment_setenv (env, "INSIDE_GNOME_BUILDER", PACKAGE_VERSION);
+
+failure:
+
+ g_clear_object (&pty);
+
+ IDE_EXIT;
+}
+
+static void
gb_terminal_workbench_addin_load (IdeWorkbenchAddin *addin,
IdeWorkbench *workbench)
{
GbTerminalWorkbenchAddin *self = (GbTerminalWorkbenchAddin *)addin;
IdePerspective *perspective;
GtkWidget *bottom_pane;
+ IdeContext *context;
+ IdeRunManager *run_manager;
g_autoptr(GSimpleAction) action = NULL;
g_assert (GB_IS_TERMINAL_WORKBENCH_ADDIN (self));
g_assert (IDE_IS_WORKBENCH (workbench));
+ context = ide_workbench_get_context (workbench);
+
ide_set_weak_pointer (&self->workbench, workbench);
action = g_simple_action_new ("new-terminal", NULL);
@@ -107,6 +200,13 @@ gb_terminal_workbench_addin_load (IdeWorkbenchAddin *addin,
bottom_pane = pnl_dock_bin_get_bottom_edge (PNL_DOCK_BIN (perspective));
gtk_container_add (GTK_CONTAINER (bottom_pane), GTK_WIDGET (self->panel_dock_widget));
+
+ run_manager = ide_context_get_run_manager (context);
+ g_signal_connect_object (run_manager,
+ "run",
+ G_CALLBACK (on_run_manager_run),
+ self,
+ G_CONNECT_SWAPPED);
}
static void
@@ -122,7 +222,13 @@ gb_terminal_workbench_addin_unload (IdeWorkbenchAddin *addin,
if (self->panel_dock_widget != NULL)
{
gtk_widget_destroy (self->panel_dock_widget);
- self->panel_dock_widget = NULL;
+ ide_clear_weak_pointer (&self->panel_dock_widget);
+ }
+
+ if (self->run_panel != NULL)
+ {
+ gtk_widget_destroy (self->run_panel);
+ ide_clear_weak_pointer (&self->run_panel);
}
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]