[gnome-builder] layout-stack: add IdeLayoutStackAddin



commit 0113cdead16dd07121a77246826bfdafef1a687c
Author: Christian Hergert <chergert redhat com>
Date:   Tue Jul 19 18:24:51 2016 -0700

    layout-stack: add IdeLayoutStackAddin
    
    This plugin interface can be used to extend the IdeLayoutStack. A new
    plugin instance will be created for each layout stack and destroyed when
    the stack is destroyed.
    
    This can be useful to add controls to the IdeLayoutStack. Doing so instead
    of using IdeLayoutView.get_controls() because it allows us to have a set
    of controls once rather than multiple times in the UI, saving widget
    overhead. This is more of a problem when using Popovers and Lists in that
    widgetry.

 libide/Makefile.am                          |    2 +
 libide/workbench/ide-layout-stack-addin.c   |  120 +++++++++++++++++++++++++++
 libide/workbench/ide-layout-stack-addin.h   |   54 ++++++++++++
 libide/workbench/ide-layout-stack-private.h |    2 +
 libide/workbench/ide-layout-stack.c         |  105 +++++++++++++++++++++++-
 5 files changed, 282 insertions(+), 1 deletions(-)
---
diff --git a/libide/Makefile.am b/libide/Makefile.am
index 7966d44..0374543 100644
--- a/libide/Makefile.am
+++ b/libide/Makefile.am
@@ -154,6 +154,7 @@ libide_1_0_la_public_headers =                            \
        workbench/ide-layout-pane.h                       \
        workbench/ide-layout-stack-split.h                \
        workbench/ide-layout-stack.h                      \
+       workbench/ide-layout-stack-addin.h                \
        workbench/ide-layout-view.h                       \
        workbench/ide-layout.h                            \
        workbench/ide-omni-bar.h                          \
@@ -300,6 +301,7 @@ libide_1_0_la_public_sources =                            \
        workbench/ide-layout-grid.c                       \
        workbench/ide-layout-pane.c                       \
        workbench/ide-layout-stack.c                      \
+       workbench/ide-layout-stack-addin.c                \
        workbench/ide-layout-view.c                       \
        workbench/ide-layout.c                            \
        workbench/ide-omni-bar.c                          \
diff --git a/libide/workbench/ide-layout-stack-addin.c b/libide/workbench/ide-layout-stack-addin.c
new file mode 100644
index 0000000..04bc83e
--- /dev/null
+++ b/libide/workbench/ide-layout-stack-addin.c
@@ -0,0 +1,120 @@
+/* ide-layout-stack-addin.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-layout-stack-addin"
+
+#include "ide-layout-stack-addin.h"
+
+G_DEFINE_INTERFACE (IdeLayoutStackAddin, ide_layout_stack_addin, G_TYPE_OBJECT)
+
+static void
+ide_layout_stack_addin_real_load (IdeLayoutStackAddin *self,
+                                  IdeLayoutStack      *stack)
+{
+  g_assert (IDE_IS_LAYOUT_STACK_ADDIN (self));
+  g_assert (IDE_IS_LAYOUT_STACK (stack));
+
+}
+
+static void
+ide_layout_stack_addin_real_unload (IdeLayoutStackAddin *self,
+                                    IdeLayoutStack      *stack)
+{
+  g_assert (IDE_IS_LAYOUT_STACK_ADDIN (self));
+  g_assert (IDE_IS_LAYOUT_STACK (stack));
+
+}
+
+static void
+ide_layout_stack_addin_real_set_view (IdeLayoutStackAddin *self,
+                                      IdeLayoutView       *view)
+{
+  g_assert (IDE_IS_LAYOUT_STACK_ADDIN (self));
+  g_assert (!view || IDE_IS_LAYOUT_VIEW (view));
+
+}
+
+static void
+ide_layout_stack_addin_default_init (IdeLayoutStackAddinInterface *iface)
+{
+  iface->load = ide_layout_stack_addin_real_load;
+  iface->unload = ide_layout_stack_addin_real_unload;
+  iface->set_view = ide_layout_stack_addin_real_set_view;
+}
+
+/**
+ * ide_layout_stack_addin_load:
+ * @self: An #IdeLayoutStackAddin
+ * @stack: An #IdeLayoutStack
+ *
+ * This function should be implemented by #IdeLayoutStackAddin plugins
+ * in #IdeLayoutStackAddinInterface.
+ *
+ * This virtual method is called when the plugin should load itself.
+ * A new instance of the plugin is created for every #IdeLayoutStack
+ * that is created in Builder.
+ */
+void
+ide_layout_stack_addin_load (IdeLayoutStackAddin *self,
+                             IdeLayoutStack      *stack)
+{
+  g_return_if_fail (IDE_IS_LAYOUT_STACK_ADDIN (self));
+  g_return_if_fail (IDE_IS_LAYOUT_STACK (stack));
+
+  IDE_LAYOUT_STACK_ADDIN_GET_IFACE (self)->load (self, stack);
+}
+
+/**
+ * ide_layout_stack_addin_unload:
+ * @self: An #IdeLayoutStackAddin
+ * @stack: An #IdeLayoutStack
+ *
+ * This function should be implemented by #IdeLayoutStackAddin plugins
+ * in #IdeLayoutStackAddinInterface.
+ *
+ * This virtual method is called when the plugin should unload itself.
+ * It should revert anything performed via ide_layout_stack_addin_load().
+ */
+void
+ide_layout_stack_addin_unload (IdeLayoutStackAddin *self,
+                               IdeLayoutStack      *stack)
+{
+  g_return_if_fail (IDE_IS_LAYOUT_STACK_ADDIN (self));
+  g_return_if_fail (IDE_IS_LAYOUT_STACK (stack));
+
+  IDE_LAYOUT_STACK_ADDIN_GET_IFACE (self)->unload (self, stack);
+}
+
+/**
+ * ide_layout_stack_addin_set_view:
+ * @self: A #IdeLayoutStackAddin
+ * @view: (nullable): An #IdeLayoutView or %NULL.
+ *
+ * This virtual method is called whenever the active view changes
+ * in the #IdeLayoutView. Plugins may want to alter what controls
+ * are displayed on the stack based on the current view.
+ */
+void
+ide_layout_stack_addin_set_view (IdeLayoutStackAddin *self,
+                                 IdeLayoutView       *view)
+{
+  g_return_if_fail (IDE_IS_LAYOUT_STACK_ADDIN (self));
+  g_return_if_fail (!view || IDE_IS_LAYOUT_VIEW (view));
+
+  IDE_LAYOUT_STACK_ADDIN_GET_IFACE (self)->set_view (self, view);
+}
diff --git a/libide/workbench/ide-layout-stack-addin.h b/libide/workbench/ide-layout-stack-addin.h
new file mode 100644
index 0000000..9ee8ca2
--- /dev/null
+++ b/libide/workbench/ide-layout-stack-addin.h
@@ -0,0 +1,54 @@
+/* ide-layout-stack-addin.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 IDE_LAYOUT_STACK_ADDIN_H
+#define IDE_LAYOUT_STACK_ADDIN_H
+
+#include <gtk/gtk.h>
+
+#include "workbench/ide-layout-stack.h"
+#include "workbench/ide-layout-view.h"
+
+G_BEGIN_DECLS
+
+#define IDE_TYPE_LAYOUT_STACK_ADDIN (ide_layout_stack_addin_get_type())
+
+G_DECLARE_INTERFACE (IdeLayoutStackAddin, ide_layout_stack_addin, IDE, LAYOUT_STACK_ADDIN, GObject)
+
+struct _IdeLayoutStackAddinInterface
+{
+  GTypeInterface parent_iface;
+
+  void (*load)     (IdeLayoutStackAddin *self,
+                    IdeLayoutStack      *stack);
+  void (*unload)   (IdeLayoutStackAddin *self,
+                    IdeLayoutStack      *stack);
+  void (*set_view) (IdeLayoutStackAddin *self,
+                    IdeLayoutView       *view);
+};
+
+void ide_layout_stack_addin_load     (IdeLayoutStackAddin *self,
+                                      IdeLayoutStack      *stack);
+void ide_layout_stack_addin_unload   (IdeLayoutStackAddin *self,
+                                      IdeLayoutStack      *stack);
+void ide_layout_stack_addin_set_view (IdeLayoutStackAddin *self,
+                                      IdeLayoutView       *view);
+
+G_END_DECLS
+
+#endif /* IDE_LAYOUT_STACK_ADDIN_H */
diff --git a/libide/workbench/ide-layout-stack-private.h b/libide/workbench/ide-layout-stack-private.h
index 28cdd19..b221840 100644
--- a/libide/workbench/ide-layout-stack-private.h
+++ b/libide/workbench/ide-layout-stack-private.h
@@ -19,6 +19,7 @@
 #ifndef IDE_LAYOUT_STACK_PRIVATE_H
 #define IDE_LAYOUT_STACK_PRIVATE_H
 
+#include <libpeas/peas.h>
 #include <gtk/gtk.h>
 
 #include "ide-context.h"
@@ -33,6 +34,7 @@ struct _IdeLayoutStack
   GtkBin              parent_instance;
 
   GSimpleActionGroup *actions;
+  PeasExtensionSet   *addins;
   GList              *focus_history;
   IdeBackForwardList *back_forward_list;
   GtkGesture         *swipe_gesture;
diff --git a/libide/workbench/ide-layout-stack.c b/libide/workbench/ide-layout-stack.c
index a1ecd56..a94e8fc 100644
--- a/libide/workbench/ide-layout-stack.c
+++ b/libide/workbench/ide-layout-stack.c
@@ -29,10 +29,11 @@
 #include "history/ide-back-forward-item.h"
 #include "util/ide-gtk.h"
 #include "workbench/ide-layout-grid.h"
+#include "workbench/ide-layout-stack.h"
 #include "workbench/ide-layout-stack-actions.h"
+#include "workbench/ide-layout-stack-addin.h"
 #include "workbench/ide-layout-stack-private.h"
 #include "workbench/ide-layout-stack-split.h"
-#include "workbench/ide-layout-stack.h"
 #include "workbench/ide-layout-tab-bar.h"
 #include "workbench/ide-layout-view.h"
 #include "workbench/ide-workbench.h"
@@ -54,6 +55,99 @@ enum {
 static GParamSpec *properties [LAST_PROP];
 static guint       signals [LAST_SIGNAL];
 
+static void
+ide_layout_stack_propagate_active_view (PeasExtensionSet *extension_set,
+                                        PeasPluginInfo   *plugin_info,
+                                        PeasExtension    *exten,
+                                        gpointer          user_data)
+{
+  IdeLayoutStackAddin *addin = (IdeLayoutStackAddin *)exten;
+  IdeLayoutStack *self = user_data;
+
+  g_assert (PEAS_IS_EXTENSION_SET (extension_set));
+  g_assert (plugin_info != NULL);
+  g_assert (IDE_IS_LAYOUT_STACK_ADDIN (addin));
+  g_assert (IDE_IS_LAYOUT_STACK (self));
+
+  ide_layout_stack_addin_set_view (addin, IDE_LAYOUT_VIEW (self->active_view));
+}
+
+static void
+ide_layout_stack_extension_added (PeasExtensionSet *extension_set,
+                                  PeasPluginInfo   *plugin_info,
+                                  PeasExtension    *exten,
+                                  gpointer          user_data)
+{
+  IdeLayoutStackAddin *addin = (IdeLayoutStackAddin *)exten;
+  IdeLayoutStack *self = user_data;
+
+  g_assert (IDE_IS_LAYOUT_STACK (self));
+  g_assert (PEAS_IS_EXTENSION_SET (extension_set));
+  g_assert (plugin_info != NULL);
+  g_assert (IDE_IS_LAYOUT_STACK_ADDIN (addin));
+
+  ide_layout_stack_addin_load (addin, self);
+
+  /* Apply the current view immediately if possible */
+  if (IDE_IS_LAYOUT_VIEW (self->active_view))
+    ide_layout_stack_addin_set_view (addin, IDE_LAYOUT_VIEW (self->active_view));
+}
+
+static void
+ide_layout_stack_extension_removed (PeasExtensionSet *extension_set,
+                                    PeasPluginInfo   *plugin_info,
+                                    PeasExtension    *exten,
+                                    gpointer          user_data)
+{
+  IdeLayoutStackAddin *addin = (IdeLayoutStackAddin *)exten;
+  IdeLayoutStack *self = user_data;
+
+  g_assert (IDE_IS_LAYOUT_STACK (self));
+  g_assert (PEAS_IS_EXTENSION_SET (extension_set));
+  g_assert (plugin_info != NULL);
+  g_assert (IDE_IS_LAYOUT_STACK_ADDIN (addin));
+
+  /* Try to be symmetrical and unset the view first */
+  if (IDE_IS_LAYOUT_VIEW (self->active_view))
+    ide_layout_stack_addin_set_view (addin, NULL);
+
+  ide_layout_stack_addin_unload (addin, self);
+}
+
+static void
+ide_layout_stack_load_addins (IdeLayoutStack *self)
+{
+  PeasEngine *engine;
+
+  g_assert (IDE_IS_LAYOUT_STACK (self));
+
+  engine = peas_engine_get_default ();
+
+  self->addins = peas_extension_set_new (engine,
+                                         IDE_TYPE_LAYOUT_STACK_ADDIN,
+                                         NULL);
+
+  g_signal_connect (self->addins,
+                    "extension-added",
+                    G_CALLBACK (ide_layout_stack_extension_added),
+                    self);
+  g_signal_connect (self->addins,
+                    "extension-removed",
+                    G_CALLBACK (ide_layout_stack_extension_removed),
+                    self);
+
+  peas_extension_set_foreach (self->addins,
+                              ide_layout_stack_extension_added,
+                              self);
+}
+
+static void
+ide_layout_stack_unload_addins (IdeLayoutStack *self)
+{
+  g_assert (IDE_IS_LAYOUT_STACK (self));
+
+}
+
 void
 ide_layout_stack_add (GtkContainer *container,
                       GtkWidget    *child)
@@ -312,6 +406,8 @@ ide_layout_stack_destroy (GtkWidget *widget)
 {
   IdeLayoutStack *self = (IdeLayoutStack *)widget;
 
+  ide_layout_stack_unload_addins (self);
+
   self->destroyed = TRUE;
 
   GTK_WIDGET_CLASS (ide_layout_stack_parent_class)->destroy (widget);
@@ -331,6 +427,8 @@ ide_layout_stack_constructed (GObject *object)
                            G_CONNECT_SWAPPED);
 
   _ide_layout_stack_actions_init (self);
+
+  ide_layout_stack_load_addins (self);
 }
 
 static void
@@ -539,6 +637,11 @@ ide_layout_stack_set_active_view (IdeLayoutStack *self,
 
       ide_layout_tab_bar_set_view (self->tab_bar, active_view);
 
+      if (self->addins != NULL)
+        peas_extension_set_foreach (self->addins,
+                                    ide_layout_stack_propagate_active_view,
+                                    self);
+
       g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_ACTIVE_VIEW]);
     }
 }


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