[gnome-builder] GbTerminalView: add split and move



commit 7484f8592891a1eac82eaf410f8817a1e3e0ddfa
Author: Sébastien Lafargue <slafargue gnome org>
Date:   Tue Jun 30 20:33:07 2015 +0200

    GbTerminalView: add split and move
    
    https://bugzilla.gnome.org/show_bug.cgi?id=751503

 plugins/terminal/Makefile.am                   |    2 +
 plugins/terminal/gb-terminal-document.c        |  161 ++++++++++
 plugins/terminal/gb-terminal-document.h        |   36 +++
 plugins/terminal/gb-terminal-view.c            |  371 +++++++++++++++++++-----
 plugins/terminal/gb-terminal-view.h            |    3 +
 plugins/terminal/gb-terminal-view.ui           |   27 ++-
 plugins/terminal/gb-terminal-workbench-addin.c |   17 +-
 src/views/gb-view-stack.c                      |    2 +-
 8 files changed, 528 insertions(+), 91 deletions(-)
---
diff --git a/plugins/terminal/Makefile.am b/plugins/terminal/Makefile.am
index 6158fb1..816233b 100644
--- a/plugins/terminal/Makefile.am
+++ b/plugins/terminal/Makefile.am
@@ -10,6 +10,8 @@ plugin_DATA = terminal.plugin
 libterminal_la_SOURCES = \
        gb-terminal-application-addin.c \
        gb-terminal-application-addin.h \
+       gb-terminal-document.c \
+       gb-terminal-document.h \
        gb-terminal-plugin.c \
        gb-terminal-private.h \
        gb-terminal-view.c \
diff --git a/plugins/terminal/gb-terminal-document.c b/plugins/terminal/gb-terminal-document.c
new file mode 100644
index 0000000..bff728e
--- /dev/null
+++ b/plugins/terminal/gb-terminal-document.c
@@ -0,0 +1,161 @@
+/* gb-terminal-document.c
+ *
+ * Copyright (C) 2015 Sebastien Lafargue <slafargue gnome org>
+ *
+ * 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 "terminal-document"
+
+#include <glib/gi18n.h>
+
+#include "gb-terminal-document.h"
+#include "gb-terminal-view.h"
+
+struct _GbTerminalDocument
+{
+  GObjectClass   parent_instance;
+
+  gchar         *title;
+};
+
+static void gb_document_init (GbDocumentInterface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (GbTerminalDocument, gb_terminal_document, G_TYPE_OBJECT,
+                         G_IMPLEMENT_INTERFACE (GB_TYPE_DOCUMENT,
+                                                gb_document_init))
+
+enum {
+  PROP_0,
+  LAST_PROP,
+
+  /* These are overridden */
+  PROP_MODIFIED,
+  PROP_READ_ONLY,
+  PROP_TITLE
+};
+
+GbTerminalDocument *
+gb_terminal_document_new (void)
+{
+  return g_object_new (GB_TYPE_TERMINAL_DOCUMENT, NULL);
+}
+
+void
+gb_terminal_document_set_title (GbTerminalDocument *document,
+                                const gchar        *title)
+{
+  g_return_if_fail (GB_IS_TERMINAL_DOCUMENT (document));
+
+  if (document->title != title)
+    {
+      g_clear_pointer (&document->title, g_free);
+      document->title = g_strdup_printf (_("Terminal (%s)"), title);
+      g_object_notify (G_OBJECT (document), "title");
+    }
+}
+
+gboolean
+gb_terminal_document_get_modified (GbDocument *document)
+{
+  g_return_val_if_fail (GB_IS_TERMINAL_DOCUMENT (document), FALSE);
+
+  return FALSE;
+}
+
+const gchar *
+gb_terminal_document_get_title (GbDocument *document)
+{
+  GbTerminalDocument *self = (GbTerminalDocument *)document;
+
+  g_return_val_if_fail (GB_IS_TERMINAL_DOCUMENT (self), NULL);
+
+  if (self->title)
+    return self->title;
+
+  return _("Terminal");
+}
+
+static GtkWidget *
+gb_terminal_document_create_view (GbDocument *document)
+{
+  g_return_val_if_fail (GB_IS_TERMINAL_DOCUMENT (document), NULL);
+
+  return g_object_new (GB_TYPE_TERMINAL_VIEW,
+                       "document", document,
+                       "visible", TRUE,
+                       NULL);
+}
+
+static void
+gb_terminal_document_finalize (GObject *object)
+{
+  GbTerminalDocument *self = GB_TERMINAL_DOCUMENT (object);
+
+  g_clear_pointer (&self->title, g_free);
+
+  G_OBJECT_CLASS (gb_terminal_document_parent_class)->finalize (object);
+}
+
+static void
+gb_terminal_document_get_property (GObject    *object,
+                                   guint       prop_id,
+                                   GValue     *value,
+                                   GParamSpec *pspec)
+{
+  GbTerminalDocument *self = GB_TERMINAL_DOCUMENT (object);
+
+  switch (prop_id)
+    {
+      case PROP_MODIFIED:
+      g_value_set_boolean (value, gb_terminal_document_get_modified (GB_DOCUMENT (self)));
+      break;
+
+    case PROP_READ_ONLY:
+      g_value_set_boolean (value, TRUE);
+      break;
+
+    case PROP_TITLE:
+      g_value_set_string (value, gb_terminal_document_get_title (GB_DOCUMENT (self)));
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+    }
+}
+
+static void
+gb_terminal_document_class_init (GbTerminalDocumentClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+  object_class->finalize = gb_terminal_document_finalize;
+  object_class->get_property = gb_terminal_document_get_property;
+
+  g_object_class_override_property (object_class, PROP_MODIFIED, "modified");
+  g_object_class_override_property (object_class, PROP_READ_ONLY, "read-only");
+  g_object_class_override_property (object_class, PROP_TITLE, "title");
+}
+
+static void
+gb_terminal_document_init (GbTerminalDocument *self)
+{
+}
+
+static void
+gb_document_init (GbDocumentInterface *iface)
+{
+  iface->get_title = gb_terminal_document_get_title;
+  iface->create_view = gb_terminal_document_create_view;
+}
diff --git a/plugins/terminal/gb-terminal-document.h b/plugins/terminal/gb-terminal-document.h
new file mode 100644
index 0000000..94e4eac
--- /dev/null
+++ b/plugins/terminal/gb-terminal-document.h
@@ -0,0 +1,36 @@
+/* gb-terminal-document.h
+ *
+ * Copyright (C) 2015 Sebastien Lafargue <slafargue gnome org>
+ *
+ * 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_DOCUMENT_H
+#define GB_TERMINAL_DOCUMENT_H
+
+#include "gb-document.h"
+
+G_BEGIN_DECLS
+
+#define GB_TYPE_TERMINAL_DOCUMENT (gb_terminal_document_get_type())
+
+G_DECLARE_FINAL_TYPE (GbTerminalDocument, gb_terminal_document, GB, TERMINAL_DOCUMENT, GObject)
+
+GbTerminalDocument  *gb_terminal_document_new          (void);
+void                 gb_terminal_document_set_title    (GbTerminalDocument *document,
+                                                        const gchar        *title);
+
+G_END_DECLS
+
+#endif /* GB_TERMINAL_DOCUMENT_H */
diff --git a/plugins/terminal/gb-terminal-view.c b/plugins/terminal/gb-terminal-view.c
index 254d7d9..aab6952 100644
--- a/plugins/terminal/gb-terminal-view.c
+++ b/plugins/terminal/gb-terminal-view.c
@@ -20,6 +20,7 @@
 #include <ide.h>
 #include <vte/vte.h>
 
+#include "gb-terminal-document.h"
 #include "gb-terminal-view.h"
 #include "gb-view.h"
 #include "gb-widget.h"
@@ -27,22 +28,34 @@
 
 struct _GbTerminalView
 {
-  GbView       parent_instance;
+  GbView               parent_instance;
 
-  VteTerminal *terminal;
+  GbTerminalDocument  *document;
 
-  guint        has_spawned : 1;
+  VteTerminal         *terminal_top;
+  VteTerminal         *terminal_bottom;
+
+  GtkWidget           *scrolled_window_bottom;
+
+  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;
 };
 
 G_DEFINE_TYPE (GbTerminalView, gb_terminal_view, GB_TYPE_VIEW)
 
 enum {
   PROP_0,
+  PROP_DOCUMENT,
   PROP_FONT_NAME,
   LAST_PROP
 };
 
 static GParamSpec *gParamSpecs [LAST_PROP];
+
 static const GdkRGBA solarized_palette[] =
 {
   /*
@@ -67,8 +80,37 @@ static const GdkRGBA solarized_palette[] =
   { 0.992156, 0.964705, 0.890196, 1 },
 };
 
+static void gb_terminal_view_connect_terminal    (GbTerminalView *self, VteTerminal *terminal);
+
+static GbDocument *
+gb_terminal_view_get_document (GbView *view)
+{
+  g_return_val_if_fail (GB_IS_TERMINAL_VIEW (view), NULL);
+
+  return GB_DOCUMENT (GB_TERMINAL_VIEW (view)->document);
+}
+
 static void
-gb_terminal_respawn (GbTerminalView *self)
+gb_terminal_view_set_document (GbTerminalView     *view,
+                               GbTerminalDocument *document)
+{
+  g_return_if_fail (GB_IS_TERMINAL_VIEW (view));
+
+  if (view->document != document)
+    {
+      if (view->document)
+        g_clear_object (&view->document);
+
+      if (document)
+        view->document = g_object_ref (document);
+
+      g_object_notify (G_OBJECT (view), "document");
+    }
+}
+
+static void
+gb_terminal_respawn (GbTerminalView *self,
+                     VteTerminal    *terminal)
 {
   g_autoptr(GPtrArray) args = NULL;
   g_autofree gchar *workpath = NULL;
@@ -81,7 +123,7 @@ gb_terminal_respawn (GbTerminalView *self)
 
   g_assert (GB_IS_TERMINAL_VIEW (self));
 
-  vte_terminal_reset (self->terminal, TRUE, TRUE);
+  vte_terminal_reset (terminal, TRUE, TRUE);
 
   toplevel = gtk_widget_get_toplevel (GTK_WIDGET (self));
   if (!GB_IS_WORKBENCH (toplevel))
@@ -96,7 +138,7 @@ gb_terminal_respawn (GbTerminalView *self)
   g_ptr_array_add (args, vte_get_user_shell ());
   g_ptr_array_add (args, NULL);
 
-  vte_terminal_spawn_sync (self->terminal,
+  vte_terminal_spawn_sync (terminal,
                            VTE_PTY_DEFAULT | VTE_PTY_NO_LASTLOG | VTE_PTY_NO_UTMP | VTE_PTY_NO_WTMP,
                            workpath,
                            (gchar **)args->pdata,
@@ -115,7 +157,7 @@ gb_terminal_respawn (GbTerminalView *self)
       return;
     }
 
-  vte_terminal_watch_child (self->terminal, child_pid);
+  vte_terminal_watch_child (terminal, child_pid);
 }
 
 static void
@@ -129,7 +171,7 @@ child_exited_cb (VteTerminal    *terminal,
   if (!gb_widget_activate_action (GTK_WIDGET (self), "view-stack", "close", NULL))
     {
       if (!gtk_widget_in_destruction (GTK_WIDGET (terminal)))
-        gb_terminal_respawn (self);
+        gb_terminal_respawn (self, terminal);
     }
 }
 
@@ -142,10 +184,10 @@ gb_terminal_realize (GtkWidget *widget)
 
   GTK_WIDGET_CLASS (gb_terminal_view_parent_class)->realize (widget);
 
-  if (!self->has_spawned)
+  if (!self->top_has_spawned)
     {
-      self->has_spawned = TRUE;
-      gb_terminal_respawn (self);
+      self->top_has_spawned = TRUE;
+      gb_terminal_respawn (self, self->terminal_top);
     }
 }
 
@@ -178,7 +220,7 @@ size_allocate_cb (VteTerminal    *terminal,
   if ((columns < 2) || (rows < 2))
     return;
 
-  vte_terminal_set_size (self->terminal, columns, rows);
+  vte_terminal_set_size (terminal, columns, rows);
 }
 
 static void
@@ -212,8 +254,9 @@ gb_terminal_get_preferred_height (GtkWidget *widget,
 }
 
 static void
-gb_terminal_set_needs_attention (GbTerminalView *self,
-                                 gboolean        needs_attention)
+gb_terminal_set_needs_attention (GbTerminalView  *self,
+                                 gboolean         needs_attention,
+                                 GtkPositionType  position)
 {
   GtkWidget *parent;
 
@@ -223,12 +266,24 @@ gb_terminal_set_needs_attention (GbTerminalView *self,
 
   if (GTK_IS_STACK (parent) &&
       !gtk_widget_in_destruction (GTK_WIDGET (self)) &&
-      !gtk_widget_in_destruction (GTK_WIDGET (self->terminal)) &&
       !gtk_widget_in_destruction (parent))
     {
+      if (position == GTK_POS_TOP &&
+          !gtk_widget_in_destruction (GTK_WIDGET (self->terminal_top)))
+        {
+          self->top_has_needs_attention = TRUE;
+        }
+      else if (position == GTK_POS_BOTTOM &&
+               self->terminal_bottom != NULL &&
+               !gtk_widget_in_destruction (GTK_WIDGET (self->terminal_bottom)))
+        {
+          self->bottom_has_needs_attention = TRUE;
+        }
 
       gtk_container_child_set (GTK_CONTAINER (parent), GTK_WIDGET (self),
-                               "needs-attention", !!needs_attention,
+                               "needs-attention",
+                               !!(self->top_has_needs_attention || self->bottom_has_needs_attention) &&
+                               needs_attention,
                                NULL);
     }
 }
@@ -243,7 +298,28 @@ notification_received_cb (VteTerminal    *terminal,
   g_assert (GB_IS_TERMINAL_VIEW (self));
 
   if (!gtk_widget_has_focus (GTK_WIDGET (terminal)))
-    gb_terminal_set_needs_attention (self, TRUE);
+    {
+      if (terminal == self->terminal_top)
+        gb_terminal_set_needs_attention (self, TRUE, GTK_POS_TOP);
+      else if (terminal == self->terminal_bottom)
+        gb_terminal_set_needs_attention (self, TRUE, GTK_POS_BOTTOM);
+    }
+}
+
+static const gchar *
+gb_terminal_get_title (GbView *view)
+{
+  const gchar *title;
+  GbTerminalView *self = (GbTerminalView *)view;
+
+  g_assert (GB_IS_TERMINAL_VIEW (self));
+
+  if (self->bottom_has_focus)
+    title = vte_terminal_get_window_title (self->terminal_bottom);
+  else
+    title = vte_terminal_get_window_title (self->terminal_top);
+
+  return title;
 }
 
 static gboolean
@@ -251,22 +327,31 @@ focus_in_event_cb (VteTerminal    *terminal,
                    GdkEvent       *event,
                    GbTerminalView *self)
 {
+  const gchar *title;
+
   g_assert (VTE_IS_TERMINAL (terminal));
   g_assert (GB_IS_TERMINAL_VIEW (self));
 
-  gb_terminal_set_needs_attention (self, FALSE);
+  self->bottom_has_focus = (terminal != self->terminal_top);
 
-  return GDK_EVENT_PROPAGATE;
-}
+  title = gb_terminal_get_title (GB_VIEW (self));
+  if (self->document)
+    gb_terminal_document_set_title (self->document, title);
 
-static const gchar *
-gb_terminal_get_title (GbView *view)
-{
-  GbTerminalView *self = (GbTerminalView *)view;
+  if (terminal == self->terminal_top)
+    {
+      self->top_has_needs_attention = FALSE;
+      gb_terminal_set_needs_attention (self, FALSE, GTK_POS_TOP);
+    }
+  else if (terminal == self->terminal_bottom)
+    {
+      self->bottom_has_needs_attention = FALSE;
+      gb_terminal_set_needs_attention (self, FALSE, GTK_POS_BOTTOM);
+    }
 
-  g_assert (GB_IS_TERMINAL_VIEW (self));
+  g_object_notify (G_OBJECT (self), "title");
 
-  return vte_terminal_get_window_title (self->terminal);
+  return GDK_EVENT_PROPAGATE;
 }
 
 static void
@@ -299,19 +384,29 @@ style_context_changed (GtkStyleContext *style_context,
       gdk_rgba_parse (&bg, "#f6f7f8");
     }
 
-  vte_terminal_set_colors (self->terminal, &fg, &bg,
+  vte_terminal_set_colors (self->terminal_top, &fg, &bg,
                            solarized_palette,
                            G_N_ELEMENTS (solarized_palette));
+
+  if (self->terminal_bottom)
+    vte_terminal_set_colors (self->terminal_bottom, &fg, &bg,
+                             solarized_palette,
+                             G_N_ELEMENTS (solarized_palette));
 }
 
-static void
-gb_terminal_grab_focus (GtkWidget *widget)
+static GbView *
+gb_terminal_create_split (GbView *view)
 {
-  GbTerminalView *self = (GbTerminalView *)widget;
+  GbView *new_view;
 
-  g_assert (GB_IS_TERMINAL_VIEW (self));
+  g_assert (GB_IS_TERMINAL_VIEW (view));
+
+  new_view = g_object_new (GB_TYPE_TERMINAL_VIEW,
+                          "document", gb_terminal_view_get_document (view),
+                          "visible", TRUE,
+                          NULL);
 
-  gtk_widget_grab_focus (GTK_WIDGET (self->terminal));
+  return new_view;
 }
 
 static void
@@ -327,18 +422,160 @@ gb_terminal_view_set_font_name (GbTerminalView *self,
 
   if (font_desc != NULL)
     {
-      vte_terminal_set_font (self->terminal, font_desc);
+      vte_terminal_set_font (self->terminal_top, font_desc);
+
+      if (self->terminal_bottom)
+        vte_terminal_set_font (self->terminal_bottom, font_desc);
+
       pango_font_description_free (font_desc);
     }
 }
 
 static void
+gb_terminal_set_split_view (GbView   *view,
+                            gboolean  split_view)
+{
+  GbTerminalView *self = (GbTerminalView *)view;
+  GtkStyleContext *style_context;
+
+  g_assert (GB_IS_TERMINAL_VIEW (self));
+  g_return_if_fail (GB_IS_TERMINAL_VIEW (self));
+
+  if (split_view && (self->terminal_bottom != NULL))
+    return;
+
+  if (!split_view && (self->terminal_bottom == NULL))
+    return;
+
+  if (split_view)
+    {
+      style_context = gtk_widget_get_style_context (GTK_WIDGET (view));
+
+      self->terminal_bottom = g_object_new (VTE_TYPE_TERMINAL,
+                                            "audible-bell", FALSE,
+                                            "expand", TRUE,
+                                            "visible", TRUE,
+                                            NULL);
+      gtk_container_add (GTK_CONTAINER (self->scrolled_window_bottom), GTK_WIDGET (self->terminal_bottom));
+      gtk_widget_show (self->scrolled_window_bottom);
+
+      gb_terminal_view_connect_terminal (self, self->terminal_bottom);
+      style_context_changed (style_context, GB_TERMINAL_VIEW (view));
+
+      gtk_widget_grab_focus (GTK_WIDGET (self->terminal_bottom));
+
+      if (!self->bottom_has_spawned)
+        {
+          self->bottom_has_spawned = TRUE;
+          gb_terminal_respawn (self, self->terminal_bottom);
+        }
+    }
+  else
+    {
+      gtk_container_remove (GTK_CONTAINER (self->scrolled_window_bottom),
+                            GTK_WIDGET (self->terminal_bottom));
+      gtk_widget_hide (self->scrolled_window_bottom);
+
+      self->terminal_bottom = NULL;
+      self->bottom_has_spawned = FALSE;
+      gtk_widget_grab_focus (GTK_WIDGET (self->terminal_top));
+    }
+}
+
+static void
+gb_terminal_grab_focus (GtkWidget *widget)
+{
+  GbTerminalView *self = (GbTerminalView *)widget;
+
+  g_assert (GB_IS_TERMINAL_VIEW (self));
+
+  if (self->bottom_has_focus && self->terminal_bottom)
+    gtk_widget_grab_focus (GTK_WIDGET (self->terminal_bottom));
+  else
+    gtk_widget_grab_focus (GTK_WIDGET (self->terminal_top));
+}
+
+static void
+gb_terminal_view_connect_terminal (GbTerminalView *self,
+                                   VteTerminal    *terminal)
+{
+  GQuark quark;
+  guint signal_id;
+
+  g_signal_connect_object (terminal,
+                           "size-allocate",
+                           G_CALLBACK (size_allocate_cb),
+                           self,
+                           0);
+
+  g_signal_connect_object (terminal,
+                           "child-exited",
+                           G_CALLBACK (child_exited_cb),
+                           self,
+                           0);
+
+  g_signal_connect_object (terminal,
+                           "focus-in-event",
+                           G_CALLBACK (focus_in_event_cb),
+                           self,
+                           0);
+
+  g_signal_connect_object (terminal,
+                           "window-title-changed",
+                           G_CALLBACK (window_title_changed_cb),
+                           self,
+                           0);
+
+  if (g_signal_parse_name ("notification-received",
+                           VTE_TYPE_TERMINAL,
+                           &signal_id,
+                           &quark,
+                           FALSE))
+    {
+      g_signal_connect_object (terminal,
+                               "notification-received",
+                               G_CALLBACK (notification_received_cb),
+                               self,
+                               0);
+    }
+}
+
+static void
+gb_terminal_view_finalize (GObject *object)
+{
+  GbTerminalView *self = GB_TERMINAL_VIEW (object);
+
+  g_clear_object (&self->document);
+
+  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_DOCUMENT:
+      g_value_set_object (value, self->document);
+      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,
                                GParamSpec   *pspec)
 {
-  GbTerminalView *self = (GbTerminalView *)object;
+  GbTerminalView *self = GB_TERMINAL_VIEW (object);
 
   switch (prop_id)
     {
@@ -346,6 +583,10 @@ gb_terminal_view_set_property (GObject      *object,
       gb_terminal_view_set_font_name (self, g_value_get_string (value));
       break;
 
+    case PROP_DOCUMENT:
+      gb_terminal_view_set_document (self, g_value_get_object (value));
+      break;
+
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
     }
@@ -358,6 +599,8 @@ gb_terminal_view_class_init (GbTerminalViewClass *klass)
   GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
   GbViewClass *view_class = GB_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;
@@ -366,6 +609,22 @@ gb_terminal_view_class_init (GbTerminalViewClass *klass)
   widget_class->grab_focus = gb_terminal_grab_focus;
 
   view_class->get_title = gb_terminal_get_title;
+  view_class->get_document = gb_terminal_view_get_document;
+  view_class->create_split = gb_terminal_create_split;
+  view_class->set_split_view =  gb_terminal_set_split_view;
+
+  gtk_widget_class_set_template_from_resource (widget_class, 
"/org/gnome/builder/plugins/terminal/gb-terminal-view.ui");
+  gtk_widget_class_bind_template_child (widget_class, GbTerminalView, terminal_top);
+  gtk_widget_class_bind_template_child (widget_class, GbTerminalView, scrolled_window_bottom);
+
+  g_type_ensure (VTE_TYPE_TERMINAL);
+
+  gParamSpecs [PROP_DOCUMENT] =
+    g_param_spec_object ("document",
+                         _("Document"),
+                         _("The document for the Vte Terminal view."),
+                         GB_TYPE_TERMINAL_DOCUMENT,
+                         (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
 
   gParamSpecs [PROP_FONT_NAME] =
     g_param_spec_string ("font-name",
@@ -375,11 +634,6 @@ gb_terminal_view_class_init (GbTerminalViewClass *klass)
                          (G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS));
 
   g_object_class_install_properties (object_class, LAST_PROP, gParamSpecs);
-
-  gtk_widget_class_set_template_from_resource (widget_class, 
"/org/gnome/builder/plugins/terminal/gb-terminal-view.ui");
-  gtk_widget_class_bind_template_child (widget_class, GbTerminalView, terminal);
-
-  g_type_ensure (VTE_TYPE_TERMINAL);
 }
 
 static void
@@ -387,47 +641,10 @@ gb_terminal_view_init (GbTerminalView *self)
 {
   GtkStyleContext *style_context;
   g_autoptr(GSettings) settings = NULL;
-  GQuark quark;
-  guint signal_id;
 
   gtk_widget_init_template (GTK_WIDGET (self));
 
-  g_signal_connect_object (self->terminal,
-                           "size-allocate",
-                           G_CALLBACK (size_allocate_cb),
-                           self,
-                           0);
-
-  g_signal_connect_object (self->terminal,
-                           "child-exited",
-                           G_CALLBACK (child_exited_cb),
-                           self,
-                           0);
-
-  g_signal_connect_object (self->terminal,
-                           "focus-in-event",
-                           G_CALLBACK (focus_in_event_cb),
-                           self,
-                           0);
-
-  g_signal_connect_object (self->terminal,
-                           "window-title-changed",
-                           G_CALLBACK (window_title_changed_cb),
-                           self,
-                           0);
-
-  if (g_signal_parse_name ("notification-received",
-                           VTE_TYPE_TERMINAL,
-                           &signal_id,
-                           &quark,
-                           FALSE))
-    {
-      g_signal_connect_object (self->terminal,
-                               "notification-received",
-                               G_CALLBACK (notification_received_cb),
-                               self,
-                               0);
-    }
+  gb_terminal_view_connect_terminal (self, self->terminal_top);
 
   /*
    * FIXME: Should we allow setting the terminal font independently from editor?
diff --git a/plugins/terminal/gb-terminal-view.h b/plugins/terminal/gb-terminal-view.h
index 94c3a8d..da25f74 100644
--- a/plugins/terminal/gb-terminal-view.h
+++ b/plugins/terminal/gb-terminal-view.h
@@ -19,6 +19,7 @@
 #ifndef GB_TERMINAL_VIEW_H
 #define GB_TERMINAL_VIEW_H
 
+#include "gb-terminal-document.h"
 #include "gb-view.h"
 
 G_BEGIN_DECLS
@@ -27,6 +28,8 @@ G_BEGIN_DECLS
 
 G_DECLARE_FINAL_TYPE (GbTerminalView, gb_terminal_view, GB, TERMINAL_VIEW, GbView)
 
+GbView *gb_terminal_view_new      (GbTerminalDocument *document);
+
 G_END_DECLS
 
 #endif /* GB_TERMINAL_VIEW_H */
diff --git a/plugins/terminal/gb-terminal-view.ui b/plugins/terminal/gb-terminal-view.ui
index bbc89f0..da1c1a3 100644
--- a/plugins/terminal/gb-terminal-view.ui
+++ b/plugins/terminal/gb-terminal-view.ui
@@ -4,15 +4,36 @@
   <template class="GbTerminalView" parent="GbView">
     <property name="visible">true</property>
     <child>
-      <object class="GtkScrolledWindow" id="scrolled_window">
+      <object class="GtkPaned" id="paned">
         <property name="expand">true</property>
+        <property name="orientation">vertical</property>
         <property name="visible">true</property>
         <child>
-          <object class="VteTerminal" id="terminal">
-            <property name="audible-bell">false</property>
+          <object class="GtkScrolledWindow" id="scrolled_window_top">
             <property name="expand">true</property>
             <property name="visible">true</property>
+            <child>
+              <object class="VteTerminal" id="terminal_top">
+                <property name="audible-bell">false</property>
+                <property name="expand">true</property>
+                <property name="visible">true</property>
+              </object>
+            </child>
           </object>
+          <packing>
+            <property name="resize">true</property>
+            <property name="shrink">true</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkScrolledWindow" id="scrolled_window_bottom">
+            <property name="expand">true</property>
+            <property name="visible">false</property>
+          </object>
+          <packing>
+            <property name="resize">true</property>
+            <property name="shrink">true</property>
+          </packing>
         </child>
       </object>
     </child>
diff --git a/plugins/terminal/gb-terminal-workbench-addin.c b/plugins/terminal/gb-terminal-workbench-addin.c
index ca91c76..944004e 100644
--- a/plugins/terminal/gb-terminal-workbench-addin.c
+++ b/plugins/terminal/gb-terminal-workbench-addin.c
@@ -19,6 +19,7 @@
 #include <glib/gi18n.h>
 
 #include "gb-terminal-view.h"
+#include "gb-terminal-document.h"
 #include "gb-terminal-workbench-addin.h"
 #include "gb-view-grid.h"
 #include "gb-workspace.h"
@@ -53,20 +54,16 @@ new_terminal_activate_cb (GSimpleAction   *action,
                           GVariant        *param,
                           GbTerminalWorkbenchAddin *self)
 {
-  GtkWidget *terminal;
-  GtkWidget *grid;
-  GtkWidget *stack;
+  GbTerminalDocument *document;
+  GbViewGrid *view_grid;
 
   g_assert (G_IS_SIMPLE_ACTION (action));
   g_assert (GB_IS_TERMINAL_WORKBENCH_ADDIN (self));
 
-  grid = gb_workbench_get_view_grid (self->workbench);
-  terminal = g_object_new (GB_TYPE_TERMINAL_VIEW,
-                           "visible", TRUE,
-                           NULL);
-  stack = gb_view_grid_get_last_focus (GB_VIEW_GRID (grid));
-  gtk_container_add (GTK_CONTAINER (stack), GTK_WIDGET (terminal));
-  gtk_widget_grab_focus (GTK_WIDGET (terminal));
+  view_grid = GB_VIEW_GRID (gb_workbench_get_view_grid (self->workbench));
+
+  document = g_object_new (GB_TYPE_TERMINAL_DOCUMENT, NULL);
+  gb_view_grid_focus_document (view_grid, GB_DOCUMENT (document));
 }
 
 static void
diff --git a/src/views/gb-view-stack.c b/src/views/gb-view-stack.c
index 0852655..88867a6 100644
--- a/src/views/gb-view-stack.c
+++ b/src/views/gb-view-stack.c
@@ -621,7 +621,7 @@ gb_view_stack_set_active_view (GbViewStack *self,
 
           binding = g_object_bind_property (active_view, "title",
                                             self->title_label, "label",
-                                            G_BINDING_SYNC_CREATE);
+                                            G_BINDING_DEFAULT | G_BINDING_SYNC_CREATE);
           ide_set_weak_pointer (&self->title_binding, binding);
 
           binding = g_object_bind_property (active_view, "modified",


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]