[gnome-builder/wip/chergert/headerbar: 12/34] workbench: break perspective selector into its own widget



commit 1c2201f3e356e0f108332458fbfd41ae774277f1
Author: Christian Hergert <chergert redhat com>
Date:   Mon Jun 20 15:08:05 2016 -0700

    workbench: break perspective selector into its own widget
    
    Much like the old sidebar selector, this works as a GtkMenuButton with a
    popover of the perspectives (and is mostly self-contained).
    
    The workbench can add the widget to the header bar in a simiarl way to how
    we would expect plugins to add to the header bar (although they need to
    call API to do it, and the workbench can do it from .ui files).

 libide/Makefile.am                                 |    5 +-
 libide/resources/libide.gresource.xml              |    1 +
 libide/workbench/ide-perspective-menu-button.c     |  391 ++++++++++++++++++++
 ...bar-private.h => ide-perspective-menu-button.h} |   21 +-
 libide/workbench/ide-perspective-menu-button.ui    |   39 ++
 libide/workbench/ide-perspective-switcher.c        |   39 --
 libide/workbench/ide-perspective-switcher.h        |   32 --
 libide/workbench/ide-workbench-header-bar.c        |  154 ++------
 libide/workbench/ide-workbench-header-bar.ui       |   44 ---
 libide/workbench/ide-workbench.c                   |    5 -
 libide/workbench/ide-workbench.ui                  |   13 +
 11 files changed, 485 insertions(+), 259 deletions(-)
---
diff --git a/libide/Makefile.am b/libide/Makefile.am
index 7ca7b65..84d702f 100644
--- a/libide/Makefile.am
+++ b/libide/Makefile.am
@@ -296,7 +296,6 @@ libide_1_0_la_public_sources =                            \
        workbench/ide-layout.c                            \
        workbench/ide-perspective.c                       \
        workbench/ide-workbench-addin.c                   \
-       workbench/ide-workbench-header-bar-private.h      \
        workbench/ide-workbench-header-bar.c              \
        workbench/ide-workbench-open.c                    \
        workbench/ide-workbench.c                         \
@@ -411,8 +410,8 @@ libide_1_0_la_SOURCES =                                   \
        workbench/ide-layout-tab-bar.h                    \
        workbench/ide-layout-tab.c                        \
        workbench/ide-layout-tab.h                        \
-       workbench/ide-perspective-switcher.c              \
-       workbench/ide-perspective-switcher.h              \
+       workbench/ide-perspective-menu-button.c           \
+       workbench/ide-perspective-menu-button.h           \
        workbench/ide-workbench-actions.c                 \
        workbench/ide-workbench-private.h                 \
        workers/ide-worker-manager.c                      \
diff --git a/libide/resources/libide.gresource.xml b/libide/resources/libide.gresource.xml
index 0dde9ef..c4680e5 100644
--- a/libide/resources/libide.gresource.xml
+++ b/libide/resources/libide.gresource.xml
@@ -63,6 +63,7 @@
     <file compressed="true" alias="ide-layout-stack.ui">../workbench/ide-layout-stack.ui</file>
     <file compressed="true" alias="ide-omni-search-group.ui">../search/ide-omni-search-group.ui</file>
     <file compressed="true" alias="ide-omni-search-row.ui">../search/ide-omni-search-row.ui</file>
+    <file compressed="true" 
alias="ide-perspective-menu-button.ui">../workbench/ide-perspective-menu-button.ui</file>
     <file compressed="true" alias="ide-preferences-entry.ui">../preferences/ide-preferences-entry.ui</file>
     <file compressed="true" 
alias="ide-preferences-file-chooser-button.ui">../preferences/ide-preferences-file-chooser-button.ui</file>
     <file compressed="true" 
alias="ide-preferences-font-button.ui">../preferences/ide-preferences-font-button.ui</file>
diff --git a/libide/workbench/ide-perspective-menu-button.c b/libide/workbench/ide-perspective-menu-button.c
new file mode 100644
index 0000000..1f21c9b
--- /dev/null
+++ b/libide/workbench/ide-perspective-menu-button.c
@@ -0,0 +1,391 @@
+/* ide-perspective-menu-button.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 "ide-perspective-menu-button"
+
+#include "ide-macros.h"
+
+#include "workbench/ide-perspective.h"
+#include "workbench/ide-perspective-menu-button.h"
+
+struct _IdePerspectiveMenuButton
+{
+  GtkMenuButton  parent_instance;
+
+  /* Weak references */
+  GtkWidget     *stack;
+
+  /* Template children */
+  GtkListBox    *list_box;
+  GtkPopover    *popover;
+  GtkImage      *image;
+};
+
+enum {
+  PROP_0,
+  PROP_STACK,
+  N_PROPS
+};
+
+static GParamSpec *properties [N_PROPS];
+
+G_DEFINE_TYPE (IdePerspectiveMenuButton, ide_perspective_menu_button, GTK_TYPE_MENU_BUTTON)
+
+static GtkWidget *
+ide_perspective_menu_button_create_row (IdePerspective *perspective)
+{
+  g_autofree gchar *title = NULL;
+  g_autofree gchar *icon_name = NULL;
+  GtkListBoxRow *row;
+  GtkLabel *label;
+  GtkImage *image;
+  GtkBox *box;
+
+  g_assert (IDE_IS_PERSPECTIVE (perspective));
+
+  title = ide_perspective_get_title (perspective);
+  icon_name = ide_perspective_get_icon_name (perspective);
+
+  row = g_object_new (GTK_TYPE_LIST_BOX_ROW,
+                      "can-focus", FALSE,
+                      "selectable", FALSE,
+                      "visible", TRUE,
+                      NULL);
+
+  g_object_set_data_full (G_OBJECT (row),
+                          "IDE_PERSPECTIVE_ID",
+                          ide_perspective_get_id (perspective),
+                          g_free);
+
+  g_object_set_data (G_OBJECT (row),
+                     "IDE_PERSPECTIVE_PRIORITY",
+                     GINT_TO_POINTER (ide_perspective_get_priority (perspective)));
+
+  box = g_object_new (GTK_TYPE_BOX,
+                      "visible", TRUE,
+                      NULL);
+  gtk_container_add (GTK_CONTAINER (row), GTK_WIDGET (box));
+
+  image = g_object_new (GTK_TYPE_IMAGE,
+                        "hexpand", FALSE,
+                        "icon-name", icon_name,
+                        "visible", TRUE,
+                        NULL);
+  gtk_container_add (GTK_CONTAINER (box), GTK_WIDGET (image));
+
+  label = g_object_new (GTK_TYPE_LABEL,
+                        "label", title,
+                        "hexpand", TRUE,
+                        "xalign", 0.0f,
+                        "visible", TRUE,
+                        NULL);
+  gtk_container_add (GTK_CONTAINER (box), GTK_WIDGET (label));
+
+  return GTK_WIDGET (row);
+}
+
+static void
+ide_perspective_menu_button_do_add_child (GtkWidget *widget,
+                                          gpointer   user_data)
+{
+  IdePerspectiveMenuButton *self = user_data;
+  GtkWidget *row;
+
+  g_assert (GTK_IS_WIDGET (widget));
+  g_assert (IDE_IS_PERSPECTIVE_MENU_BUTTON (self));
+
+  row = ide_perspective_menu_button_create_row (IDE_PERSPECTIVE (widget));
+  gtk_container_add (GTK_CONTAINER (self->list_box), row);
+  gtk_list_box_invalidate_sort (self->list_box);
+}
+
+static void
+ide_perspective_menu_button_add_child (IdePerspectiveMenuButton *self,
+                                       GtkWidget                *child,
+                                       GtkStack                 *stack)
+{
+  g_assert (IDE_IS_PERSPECTIVE_MENU_BUTTON (self));
+  g_assert (GTK_IS_WIDGET (child));
+  g_assert (GTK_IS_STACK (stack));
+
+  if (!IDE_IS_PERSPECTIVE (child))
+    {
+      g_warning ("Attempt to add something other than an IdePerspective to %s",
+                 G_OBJECT_TYPE_NAME (self));
+      return;
+    }
+
+  if (ide_perspective_is_early (IDE_PERSPECTIVE (child)))
+    return;
+
+  ide_perspective_menu_button_do_add_child (child, self);
+}
+
+static void
+ide_perspective_menu_button_do_remove_child (GtkWidget *widget,
+                                             gpointer   user_data)
+{
+  const gchar *id = user_data;
+  const gchar *widget_id;
+
+  g_assert (GTK_IS_LIST_BOX_ROW (widget));
+
+  widget_id = g_object_get_data (G_OBJECT (widget), "IDE_PERSPECTIVE_ID");
+
+  if (g_strcmp0 (widget_id, id) == 0)
+    gtk_widget_destroy (widget);
+}
+
+static void
+ide_perspective_menu_button_remove_child (IdePerspectiveMenuButton *self,
+                                          GtkWidget                *child,
+                                          GtkStack                 *stack)
+{
+  g_autofree gchar *id = NULL;
+
+  g_assert (IDE_IS_PERSPECTIVE_MENU_BUTTON (self));
+  g_assert (GTK_IS_WIDGET (child));
+  g_assert (GTK_IS_STACK (stack));
+
+  /* warn on addition, silent on removal */
+  if (!IDE_IS_PERSPECTIVE (child))
+    return;
+
+  id = ide_perspective_get_id (IDE_PERSPECTIVE (child));
+  if (id != NULL)
+    gtk_container_foreach (GTK_CONTAINER (self->list_box),
+                           ide_perspective_menu_button_do_remove_child,
+                           id);
+}
+
+static void
+ide_perspective_menu_button_notify_visible_child (IdePerspectiveMenuButton *self,
+                                                  GParamSpec               *pspec,
+                                                  GtkStack                 *stack)
+{
+  GtkWidget *child;
+
+  g_assert (IDE_IS_PERSPECTIVE_MENU_BUTTON (self));
+  g_assert (GTK_IS_STACK (stack));
+
+  child = gtk_stack_get_visible_child (stack);
+
+  if (IDE_IS_PERSPECTIVE (child))
+    {
+      g_autofree gchar *icon_name = NULL;
+
+      icon_name = ide_perspective_get_icon_name (IDE_PERSPECTIVE (child));
+
+      g_object_set (self->image,
+                    "icon-name", icon_name,
+                    NULL);
+    }
+}
+
+static void
+ide_perspective_menu_button_disconnect (IdePerspectiveMenuButton *self)
+{
+  g_assert (IDE_IS_PERSPECTIVE_MENU_BUTTON (self));
+  g_assert (GTK_IS_STACK (self->stack));
+
+  g_signal_handlers_disconnect_by_func (self->stack,
+                                        G_CALLBACK (ide_perspective_menu_button_add_child),
+                                        self);
+  g_signal_handlers_disconnect_by_func (self->stack,
+                                        G_CALLBACK (ide_perspective_menu_button_remove_child),
+                                        self);
+  g_signal_handlers_disconnect_by_func (self->stack,
+                                        G_CALLBACK (ide_perspective_menu_button_notify_visible_child),
+                                        self);
+
+  ide_clear_weak_pointer (&self->stack);
+}
+
+static void
+ide_perspective_menu_button_connect (IdePerspectiveMenuButton *self,
+                                     GtkWidget                *stack)
+{
+  g_assert (IDE_IS_PERSPECTIVE_MENU_BUTTON (self));
+  g_assert (GTK_IS_STACK (stack));
+
+  ide_set_weak_pointer (&self->stack, stack);
+
+  g_signal_connect_object (stack,
+                           "add",
+                           G_CALLBACK (ide_perspective_menu_button_add_child),
+                           self,
+                           G_CONNECT_SWAPPED);
+
+  g_signal_connect_object (stack,
+                           "remove",
+                           G_CALLBACK (ide_perspective_menu_button_remove_child),
+                           self,
+                           G_CONNECT_SWAPPED);
+
+  g_signal_connect_object (stack,
+                           "notify::visible-child",
+                           G_CALLBACK (ide_perspective_menu_button_notify_visible_child),
+                           self,
+                           G_CONNECT_SWAPPED);
+
+  gtk_container_foreach (GTK_CONTAINER (stack),
+                         ide_perspective_menu_button_do_add_child,
+                         self);
+}
+
+static void
+ide_perspective_menu_button_row_activated (IdePerspectiveMenuButton *self,
+                                           GtkListBoxRow            *row,
+                                           GtkListBox               *list_box)
+{
+  const gchar *id;
+
+  g_assert (IDE_IS_PERSPECTIVE_MENU_BUTTON (self));
+  g_assert (GTK_IS_LIST_BOX_ROW (row));
+  g_assert (GTK_IS_LIST_BOX (list_box));
+
+  id = g_object_get_data (G_OBJECT (row), "IDE_PERSPECTIVE_ID");
+
+  if (id != NULL && GTK_IS_STACK (self->stack))
+    {
+      gtk_stack_set_visible_child_name (GTK_STACK (self->stack), id);
+      gtk_widget_hide (GTK_WIDGET (self->popover));
+    }
+}
+
+static gint
+list_box_sort (GtkListBoxRow *row1,
+               GtkListBoxRow *row2,
+               gpointer       user_data)
+{
+  gpointer priority1;
+  gpointer priority2;
+
+  priority1 = g_object_get_data (G_OBJECT (row1), "IDE_PERSPECTIVE_PRIORITY");
+  priority2 = g_object_get_data (G_OBJECT (row2), "IDE_PERSPECTIVE_PRIORITY");
+
+  return GPOINTER_TO_INT (priority1) - GPOINTER_TO_INT (priority2);
+}
+
+static void
+ide_perspective_menu_button_get_property (GObject    *object,
+                                          guint       prop_id,
+                                          GValue     *value,
+                                          GParamSpec *pspec)
+{
+  IdePerspectiveMenuButton *self = IDE_PERSPECTIVE_MENU_BUTTON (object);
+
+  switch (prop_id)
+    {
+    case PROP_STACK:
+      g_value_set_object (value, ide_perspective_menu_button_get_stack (self));
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+    }
+}
+
+static void
+ide_perspective_menu_button_set_property (GObject      *object,
+                                          guint         prop_id,
+                                          const GValue *value,
+                                          GParamSpec   *pspec)
+{
+  IdePerspectiveMenuButton *self = IDE_PERSPECTIVE_MENU_BUTTON (object);
+
+  switch (prop_id)
+    {
+    case PROP_STACK:
+      ide_perspective_menu_button_set_stack (self, g_value_get_object (value));
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+    }
+}
+
+static void
+ide_perspective_menu_button_class_init (IdePerspectiveMenuButtonClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+  GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+
+  object_class->get_property = ide_perspective_menu_button_get_property;
+  object_class->set_property = ide_perspective_menu_button_set_property;
+
+  properties [PROP_STACK] =
+    g_param_spec_object ("stack",
+                         "Stack",
+                         "The perspectives stack",
+                         GTK_TYPE_STACK,
+
+                         (G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_properties (object_class, N_PROPS, properties);
+
+  gtk_widget_class_set_template_from_resource (widget_class, 
"/org/gnome/builder/ui/ide-perspective-menu-button.ui");
+  gtk_widget_class_bind_template_child (widget_class, IdePerspectiveMenuButton, image);
+  gtk_widget_class_bind_template_child (widget_class, IdePerspectiveMenuButton, list_box);
+  gtk_widget_class_bind_template_child (widget_class, IdePerspectiveMenuButton, popover);
+}
+
+static void
+ide_perspective_menu_button_init (IdePerspectiveMenuButton *self)
+{
+  gtk_widget_init_template (GTK_WIDGET (self));
+
+  gtk_list_box_set_sort_func (self->list_box, list_box_sort, NULL, NULL);
+
+  g_signal_connect_object (self->list_box,
+                           "row-activated",
+                           G_CALLBACK (ide_perspective_menu_button_row_activated),
+                           self,
+                           G_CONNECT_SWAPPED);
+}
+
+/**
+ * ide_perspective_menu_button_get_stack:
+ *
+ * Returns: (nullable) (transfer none): A #GtkStack or %NULL.
+ */
+GtkWidget *
+ide_perspective_menu_button_get_stack (IdePerspectiveMenuButton *self)
+{
+  g_return_val_if_fail (IDE_IS_PERSPECTIVE_MENU_BUTTON (self), NULL);
+
+  return self->stack;
+}
+
+void
+ide_perspective_menu_button_set_stack (IdePerspectiveMenuButton *self,
+                                       GtkWidget                *stack)
+{
+  g_return_if_fail (IDE_IS_PERSPECTIVE_MENU_BUTTON (self));
+  g_return_if_fail (!stack || GTK_IS_STACK (stack));
+
+  if (stack != self->stack)
+    {
+      if (self->stack != NULL)
+        ide_perspective_menu_button_disconnect (self);
+
+      if (stack != NULL)
+        ide_perspective_menu_button_connect (self, stack);
+
+      g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_STACK]);
+    }
+}
diff --git a/libide/workbench/ide-workbench-header-bar-private.h 
b/libide/workbench/ide-perspective-menu-button.h
similarity index 54%
rename from libide/workbench/ide-workbench-header-bar-private.h
rename to libide/workbench/ide-perspective-menu-button.h
index fac5d60..09817c4 100644
--- a/libide/workbench/ide-workbench-header-bar-private.h
+++ b/libide/workbench/ide-perspective-menu-button.h
@@ -1,4 +1,4 @@
-/* ide-workbench-header-bar-private.h
+/* ide-perspective-menu-button.h
  *
  * Copyright (C) 2016 Christian Hergert <chergert redhat com>
  *
@@ -16,22 +16,19 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#ifndef IDE_WORKBENCH_HEADER_BAR_PRIVATE_H
-#define IDE_WORKBENCH_HEADER_BAR_PRIVATE_H
+#ifndef IDE_PERSPECTIVE_MENU_BUTTON_H
+#define IDE_PERSPECTIVE_MENU_BUTTON_H
 
-#include "workbench/ide-workbench-header-bar.h"
-#include "workbench/ide-perspective.h"
+#include <gtk/gtk.h>
 
 G_BEGIN_DECLS
 
-void _ide_workbench_header_bar_set_perspectives (IdeWorkbenchHeaderBar *self,
-                                                 GListModel            *model)
-  G_GNUC_INTERNAL;
+G_DECLARE_FINAL_TYPE (IdePerspectiveMenuButton, ide_perspective_menu_button, IDE, PERSPECTIVE_MENU_BUTTON, 
GtkMenuButton)
 
-void _ide_workbench_header_bar_set_perspective (IdeWorkbenchHeaderBar *self,
-                                                IdePerspective        *perspective)
-  G_GNUC_INTERNAL;
+GtkWidget *ide_perspective_menu_button_get_stack (IdePerspectiveMenuButton *self);
+void       ide_perspective_menu_button_set_stack (IdePerspectiveMenuButton *self,
+                                                  GtkWidget                *stack);
 
 G_END_DECLS
 
-#endif /* IDE_WORKBENCH_HEADER_BAR_PRIVATE_H */
+#endif /* IDE_PERSPECTIVE_MENU_BUTTON_H */
diff --git a/libide/workbench/ide-perspective-menu-button.ui b/libide/workbench/ide-perspective-menu-button.ui
new file mode 100644
index 0000000..912a694
--- /dev/null
+++ b/libide/workbench/ide-perspective-menu-button.ui
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+  <object class="GtkPopover" id="popover">
+    <style>
+      <class name="perspectives-selector"/>
+    </style>
+    <child>
+      <object class="GtkListBox" id="list_box">
+        <property name="visible">true</property>
+      </object>
+    </child>
+  </object>
+  <template class="IdePerspectiveMenuButton" parent="GtkMenuButton">
+    <property name="popover">popover</property>
+    <child>
+      <object class="GtkBox">
+        <property name="orientation">horizontal</property>
+        <property name="margin-end">8</property>
+        <property name="margin-start">8</property>
+        <property name="spacing">12</property>
+        <property name="visible">true</property>
+        <style>
+          <class name="image-button"/>
+        </style>
+        <child>
+          <object class="GtkImage" id="image">
+            <property name="visible">true</property>
+          </object>
+        </child>
+        <child>
+          <object class="GtkImage">
+            <property name="icon-name">pan-down-symbolic</property>
+            <property name="visible">true</property>
+          </object>
+        </child>
+      </object>
+    </child>
+  </template>
+</interface>
diff --git a/libide/workbench/ide-workbench-header-bar.c b/libide/workbench/ide-workbench-header-bar.c
index f6f9607..e30e856 100644
--- a/libide/workbench/ide-workbench-header-bar.c
+++ b/libide/workbench/ide-workbench-header-bar.c
@@ -25,46 +25,19 @@
 #include "workbench/ide-perspective.h"
 #include "workbench/ide-workbench.h"
 #include "workbench/ide-workbench-header-bar.h"
-#include "workbench/ide-workbench-header-bar-private.h"
 
 typedef struct
 {
   GtkMenuButton  *menu_button;
-  GtkListBox     *perspectives_list_box;
-  GtkMenuButton  *perspectives_menu_button;
-  GtkImage       *perspectives_menu_button_image;
-  GtkPopover     *perspectives_popover;
   EggPriorityBox *right_box;
   EggPriorityBox *left_box;
 } IdeWorkbenchHeaderBarPrivate;
 
-G_DEFINE_TYPE_WITH_PRIVATE (IdeWorkbenchHeaderBar, ide_workbench_header_bar, GTK_TYPE_HEADER_BAR)
+static void buildable_iface_init (GtkBuildableIface *iface);
 
-static void
-perspective_row_selected (IdeWorkbenchHeaderBar *self,
-                          GtkListBoxRow         *row,
-                          GtkListBox            *list_box)
-{
-  IdeWorkbenchHeaderBarPrivate *priv = ide_workbench_header_bar_get_instance_private (self);
-  IdeWorkbench *workbench;
-  const gchar *id;
-
-  g_assert (IDE_IS_WORKBENCH_HEADER_BAR (self));
-  g_assert (GTK_IS_LIST_BOX_ROW (row));
-  g_assert (GTK_IS_LIST_BOX (list_box));
-
-  id = g_object_get_data (G_OBJECT (row), "IDE_PERSPECTIVE_ID");
-  if (id == NULL)
-    return;
-
-  workbench = ide_widget_get_workbench (GTK_WIDGET (self));
-  if (workbench == NULL)
-    return;
-
-  gtk_widget_hide (GTK_WIDGET (priv->perspectives_popover));
-
-  ide_workbench_set_visible_perspective_name (workbench, id);
-}
+G_DEFINE_TYPE_EXTENDED (IdeWorkbenchHeaderBar, ide_workbench_header_bar, GTK_TYPE_HEADER_BAR, 0,
+                        G_ADD_PRIVATE (IdeWorkbenchHeaderBar)
+                        G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE, buildable_iface_init))
 
 GtkWidget *
 ide_workbench_header_bar_new (void)
@@ -79,10 +52,6 @@ ide_workbench_header_bar_class_init (IdeWorkbenchHeaderBarClass *klass)
 
   gtk_widget_class_set_template_from_resource (widget_class, 
"/org/gnome/builder/ui/ide-workbench-header-bar.ui");
   gtk_widget_class_bind_template_child_private (widget_class, IdeWorkbenchHeaderBar, menu_button);
-  gtk_widget_class_bind_template_child_private (widget_class, IdeWorkbenchHeaderBar, perspectives_list_box);
-  gtk_widget_class_bind_template_child_private (widget_class, IdeWorkbenchHeaderBar, 
perspectives_menu_button);
-  gtk_widget_class_bind_template_child_private (widget_class, IdeWorkbenchHeaderBar, 
perspectives_menu_button_image);
-  gtk_widget_class_bind_template_child_private (widget_class, IdeWorkbenchHeaderBar, perspectives_popover);
   gtk_widget_class_bind_template_child_private (widget_class, IdeWorkbenchHeaderBar, left_box);
   gtk_widget_class_bind_template_child_private (widget_class, IdeWorkbenchHeaderBar, right_box);
 }
@@ -99,12 +68,6 @@ ide_workbench_header_bar_init (IdeWorkbenchHeaderBar *self)
   model = ide_application_get_menu_by_id (IDE_APPLICATION_DEFAULT, "gear-menu");
   popover = gtk_popover_new_from_model (NULL, G_MENU_MODEL (model));
   gtk_menu_button_set_popover (priv->menu_button, popover);
-
-  g_signal_connect_object (priv->perspectives_list_box,
-                           "row-activated",
-                           G_CALLBACK (perspective_row_selected),
-                           self,
-                           G_CONNECT_SWAPPED);
 }
 
 void
@@ -119,89 +82,6 @@ ide_workbench_header_bar_focus_search (IdeWorkbenchHeaderBar *self)
     gtk_widget_grab_focus (GTK_WIDGET (entry));
 }
 
-static GtkWidget *
-create_perspective_row (gpointer item,
-                        gpointer user_data)
-{
-  IdePerspective *perspective = item;
-  g_autofree gchar *title = NULL;
-  g_autofree gchar *icon_name = NULL;
-  GtkListBoxRow *row;
-  GtkLabel *label;
-  GtkImage *image;
-  GtkBox *box;
-
-  g_assert (IDE_IS_PERSPECTIVE (perspective));
-
-  title = ide_perspective_get_title (perspective);
-  icon_name = ide_perspective_get_icon_name (perspective);
-
-  row = g_object_new (GTK_TYPE_LIST_BOX_ROW,
-                      "can-focus", FALSE,
-                      "selectable", FALSE,
-                      "visible", TRUE,
-                      NULL);
-
-  g_object_set_data_full (G_OBJECT (row),
-                          "IDE_PERSPECTIVE_ID",
-                          ide_perspective_get_id (perspective),
-                          g_free);
-
-  box = g_object_new (GTK_TYPE_BOX,
-                      "visible", TRUE,
-                      NULL);
-  gtk_container_add (GTK_CONTAINER (row), GTK_WIDGET (box));
-
-  image = g_object_new (GTK_TYPE_IMAGE,
-                        "hexpand", FALSE,
-                        "icon-name", icon_name,
-                        "visible", TRUE,
-                        NULL);
-  gtk_container_add (GTK_CONTAINER (box), GTK_WIDGET (image));
-
-  label = g_object_new (GTK_TYPE_LABEL,
-                        "label", title,
-                        "hexpand", TRUE,
-                        "xalign", 0.0f,
-                        "visible", TRUE,
-                        NULL);
-  gtk_container_add (GTK_CONTAINER (box), GTK_WIDGET (label));
-
-  return GTK_WIDGET (row);
-}
-
-void
-_ide_workbench_header_bar_set_perspectives (IdeWorkbenchHeaderBar *self,
-                                            GListModel            *model)
-{
-  IdeWorkbenchHeaderBarPrivate *priv = ide_workbench_header_bar_get_instance_private (self);
-
-  g_assert (IDE_IS_WORKBENCH_HEADER_BAR (self));
-  g_assert (!model || G_IS_LIST_MODEL (model));
-
-  gtk_list_box_bind_model (priv->perspectives_list_box,
-                           model,
-                           create_perspective_row,
-                           NULL, NULL);
-}
-
-void
-_ide_workbench_header_bar_set_perspective (IdeWorkbenchHeaderBar *self,
-                                           IdePerspective        *perspective)
-{
-  IdeWorkbenchHeaderBarPrivate *priv = ide_workbench_header_bar_get_instance_private (self);
-  g_autofree gchar *icon_name = NULL;
-
-  g_assert (IDE_IS_WORKBENCH_HEADER_BAR (self));
-  g_assert (IDE_IS_PERSPECTIVE (perspective));
-
-  icon_name = ide_perspective_get_icon_name (perspective);
-
-  g_object_set (priv->perspectives_menu_button_image,
-                "icon-name", icon_name,
-                NULL);
-}
-
 void
 ide_workbench_header_bar_insert_left (IdeWorkbenchHeaderBar *self,
                                       GtkWidget             *widget,
@@ -237,3 +117,29 @@ ide_workbench_header_bar_insert_right (IdeWorkbenchHeaderBar *self,
                                      "priority", priority,
                                      NULL);
 }
+
+static GObject *
+ide_workbench_header_bar_get_internal_child (GtkBuildable *buildable,
+                                             GtkBuilder   *builder,
+                                             const gchar  *childname)
+{
+  IdeWorkbenchHeaderBar *self = (IdeWorkbenchHeaderBar *)buildable;
+  IdeWorkbenchHeaderBarPrivate *priv = ide_workbench_header_bar_get_instance_private (self);
+
+  g_assert (GTK_IS_BUILDABLE (buildable));
+  g_assert (GTK_IS_BUILDER (builder));
+  g_assert (childname != NULL);
+
+  if (g_str_equal (childname, "left"))
+    return G_OBJECT (priv->left_box);
+  else if (g_str_equal (childname, "right"))
+    return G_OBJECT (priv->right_box);
+  else
+    return NULL;
+}
+
+static void
+buildable_iface_init (GtkBuildableIface *iface)
+{
+  iface->get_internal_child = ide_workbench_header_bar_get_internal_child;
+}
diff --git a/libide/workbench/ide-workbench-header-bar.ui b/libide/workbench/ide-workbench-header-bar.ui
index b42be60..5e04e51 100644
--- a/libide/workbench/ide-workbench-header-bar.ui
+++ b/libide/workbench/ide-workbench-header-bar.ui
@@ -1,53 +1,9 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <interface>
-  <object class="GtkPopover" id="perspectives_popover">
-    <property name="width-request">250</property>
-    <style>
-      <class name="perspectives-selector"/>
-    </style>
-    <child>
-      <object class="GtkListBox" id="perspectives_list_box">
-        <property name="visible">true</property>
-      </object>
-    </child>
-  </object>
   <!-- interface-requires gtk+ 3.21 -->
   <template class="IdeWorkbenchHeaderBar" parent="GtkHeaderBar">
     <property name="show-close-button">true</property>
     <child>
-      <object class="GtkMenuButton" id="perspectives_menu_button">
-        <property name="popover">perspectives_popover</property>
-        <property name="visible">true</property>
-        <style>
-          <class name="image-button"/>
-        </style>
-        <child>
-          <object class="GtkBox">
-            <property name="margin-end">8</property>
-            <property name="margin-start">8</property>
-            <property name="spacing">12</property>
-            <property name="visible">true</property>
-            <child>
-              <object class="GtkImage" id="perspectives_menu_button_image">
-                <property name="icon-name">builder-editor-symbolic</property>
-                <property name="visible">true</property>
-              </object>
-            </child>
-            <child>
-              <object class="GtkImage">
-                <property name="icon-name">pan-down-symbolic</property>
-                <property name="visible">true</property>
-              </object>
-            </child>
-          </object>
-        </child>
-      </object>
-      <packing>
-        <property name="pack-type">start</property>
-        <property name="position">0</property>
-      </packing>
-    </child>
-    <child>
       <object class="EggPriorityBox" id="left_box">
         <property name="hexpand">true</property>
         <property name="visible">true</property>
diff --git a/libide/workbench/ide-workbench.c b/libide/workbench/ide-workbench.c
index 1e1d8ea..f18f839 100644
--- a/libide/workbench/ide-workbench.c
+++ b/libide/workbench/ide-workbench.c
@@ -34,7 +34,6 @@
 #include "workbench/ide-layout.h"
 #include "workbench/ide-workbench-addin.h"
 #include "workbench/ide-workbench-header-bar.h"
-#include "workbench/ide-workbench-header-bar-private.h"
 #include "workbench/ide-workbench-private.h"
 #include "workbench/ide-workbench.h"
 
@@ -377,8 +376,6 @@ ide_workbench_init (IdeWorkbench *self)
   gtk_widget_init_template (GTK_WIDGET (self));
 
   self->perspectives = g_list_store_new (IDE_TYPE_PERSPECTIVE);
-  _ide_workbench_header_bar_set_perspectives (self->header_bar,
-                                              G_LIST_MODEL (self->perspectives));
 
   ide_workbench_add_perspective (self,
                                  g_object_new (IDE_TYPE_GREETER_PERSPECTIVE,
@@ -766,8 +763,6 @@ ide_workbench_set_visible_perspective (IdeWorkbench   *self,
 
   /* TODO: Possibly remove some perspectives */
 
-  _ide_workbench_header_bar_set_perspective (self->header_bar, perspective);
-
   if (self->addins != NULL)
     peas_extension_set_foreach (self->addins,
                                 ide_workbench_notify_perspective_set,
diff --git a/libide/workbench/ide-workbench.ui b/libide/workbench/ide-workbench.ui
index e8bb964..2c5454a 100644
--- a/libide/workbench/ide-workbench.ui
+++ b/libide/workbench/ide-workbench.ui
@@ -5,6 +5,19 @@
     <child type="titlebar">
       <object class="IdeWorkbenchHeaderBar" id="header_bar">
         <property name="visible">true</property>
+        <child internal-child="left">
+          <object class="EggPriorityBox">
+            <child>
+              <object class="IdePerspectiveMenuButton">
+                <property name="stack">perspectives_stack</property>
+                <property name="visible">true</property>
+              </object>
+              <packing>
+                <property name="priority">-100000</property>
+              </packing>
+            </child>
+          </object>
+        </child>
       </object>
     </child>
     <child>


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