[gnome-todo/wip/gbsneto/plugins] window: load plugins' header widgets



commit 2881d8f8db039bc0df6c62a5c5a428eaaeea01ed
Author: Georges Basile Stavracas Neto <georges stavracas gmail com>
Date:   Sat Jan 16 15:09:10 2016 -0200

    window: load plugins' header widgets
    
    They are loaded into the headerbar and positioned
    according to their halign property.

 data/ui/window.ui                |   40 +++++++
 plugins/eds/gtd-plugin-eds.c     |    7 +
 src/gtd-window.c                 |  238 +++++++++++++++++++++++++++++++++----
 src/interfaces/gtd-activatable.c |   17 +++
 src/interfaces/gtd-activatable.h |    4 +
 5 files changed, 280 insertions(+), 26 deletions(-)
---
diff --git a/data/ui/window.ui b/data/ui/window.ui
index 0004a56..a115b7d 100644
--- a/data/ui/window.ui
+++ b/data/ui/window.ui
@@ -52,6 +52,26 @@
           </object>
         </child>
         <child>
+          <object class="GtkBox" id="panel_box_start">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="spacing">6</property>
+          </object>
+          <packing>
+            <property name="pack_type">start</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkBox" id="extension_box_start">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="spacing">6</property>
+          </object>
+          <packing>
+            <property name="pack_type">start</property>
+          </packing>
+        </child>
+        <child>
           <object class="GtkButton" id="cancel_selection_button">
             <property name="visible">False</property>
             <property name="can_focus">True</property>
@@ -82,6 +102,26 @@
             <property name="pack_type">end</property>
           </packing>
         </child>
+        <child>
+          <object class="GtkBox" id="panel_box_end">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="spacing">6</property>
+          </object>
+          <packing>
+            <property name="pack_type">end</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkBox" id="extension_box_end">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="spacing">6</property>
+          </object>
+          <packing>
+            <property name="pack_type">end</property>
+          </packing>
+        </child>
       </object>
     </child>
   </template>
diff --git a/plugins/eds/gtd-plugin-eds.c b/plugins/eds/gtd-plugin-eds.c
index b644128..6ca83a3 100644
--- a/plugins/eds/gtd-plugin-eds.c
+++ b/plugins/eds/gtd-plugin-eds.c
@@ -116,6 +116,12 @@ peas_activatable_iface_init (PeasActivatableInterface *iface)
 /*
  * GtdActivatable interface implementation
  */
+static GList*
+gtd_plugin_eds_get_header_widgets (GtdActivatable *activatable)
+{
+  return NULL;
+}
+
 static GtkWidget*
 gtd_plugin_eds_get_preferences_panel (GtdActivatable *activatable)
 {
@@ -141,6 +147,7 @@ gtd_plugin_eds_get_providers (GtdActivatable *activatable)
 static void
 gtd_activatable_iface_init (GtdActivatableInterface *iface)
 {
+  iface->get_header_widgets = gtd_plugin_eds_get_header_widgets;
   iface->get_preferences_panel = gtd_plugin_eds_get_preferences_panel;
   iface->get_panels = gtd_plugin_eds_get_panels;
   iface->get_providers = gtd_plugin_eds_get_providers;
diff --git a/src/gtd-window.c b/src/gtd-window.c
index a24392c..1b9f73e 100644
--- a/src/gtd-window.c
+++ b/src/gtd-window.c
@@ -16,13 +16,16 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
+#include "interfaces/gtd-activatable.h"
 #include "interfaces/gtd-provider.h"
 #include "interfaces/gtd-panel.h"
 #include "views/gtd-list-selector-panel.h"
+#include "plugin/gtd-plugin-manager.h"
 #include "gtd-application.h"
 #include "gtd-enum-types.h"
 #include "gtd-task-list-view.h"
 #include "gtd-manager.h"
+#include "gtd-manager-protected.h"
 #include "gtd-notification.h"
 #include "gtd-notification-widget.h"
 #include "gtd-provider-dialog.h"
@@ -43,6 +46,12 @@ typedef struct
   GtkStackSwitcher              *stack_switcher;
   GtdProviderDialog             *provider_dialog;
 
+  /* boxes */
+  GtkWidget                     *extension_box_end;
+  GtkWidget                     *extension_box_start;
+  GtkWidget                     *panel_box_end;
+  GtkWidget                     *panel_box_start;
+
   GtdPanel                      *active_panel;
 
   /* mode */
@@ -91,6 +100,172 @@ typedef struct
 } ErrorData;
 
 static void
+add_widgets (GtdWindow *window,
+             GtkWidget *container_start,
+             GtkWidget *container_end,
+             GList     *widgets)
+{
+  GtdWindowPrivate *priv = gtd_window_get_instance_private (window);
+  GList *l;
+
+  for (l = widgets; l != NULL; l = l->next)
+    {
+      switch (gtk_widget_get_halign (l->data))
+        {
+        case GTK_ALIGN_START:
+          gtk_box_pack_start (GTK_BOX (container_start),
+                              l->data,
+                              FALSE,
+                              FALSE,
+                              0);
+          break;
+
+        case GTK_ALIGN_CENTER:
+          gtk_header_bar_set_custom_title (priv->headerbar, l->data);
+          break;
+
+        case GTK_ALIGN_END:
+          gtk_box_pack_end (GTK_BOX (container_end),
+                            l->data,
+                            FALSE,
+                            FALSE,
+                            0);
+          break;
+
+        case GTK_ALIGN_BASELINE:
+        case GTK_ALIGN_FILL:
+        default:
+          gtk_box_pack_start (GTK_BOX (container_start),
+                              l->data,
+                              FALSE,
+                              FALSE,
+                              0);
+          break;
+        }
+    }
+}
+
+static void
+remove_widgets (GtdWindow *window,
+                GtkWidget *container_start,
+                GtkWidget *container_end,
+                GList     *widgets)
+{
+  GtdWindowPrivate *priv = gtd_window_get_instance_private (window);
+  GList *l;
+
+  for (l = widgets; l != NULL; l = l->next)
+    {
+      GtkWidget *container;
+
+      if (gtk_widget_get_halign (l->data) == GTK_ALIGN_END)
+        container = container_end;
+      else if (gtk_widget_get_halign (l->data) == GTK_ALIGN_CENTER)
+        container = GTK_WIDGET (priv->headerbar);
+      else
+        container = container_start;
+
+      g_object_ref (l->data);
+      gtk_container_remove (GTK_CONTAINER (container), l->data);
+    }
+}
+
+static void
+on_active_change (GtdActivatable *activatable,
+                  GParamSpec     *pspec,
+                  GtdWindow      *window)
+{
+  GtdWindowPrivate *priv;
+  GList *header_widgets;
+  gboolean active;
+
+  priv = gtd_window_get_instance_private (window);
+  header_widgets = gtd_activatable_get_header_widgets (activatable);
+
+  g_object_get (activatable,
+                "active", &active,
+                NULL);
+
+  if (active)
+    {
+      add_widgets (window,
+                   priv->extension_box_start,
+                   priv->extension_box_end,
+                   header_widgets);
+    }
+  else
+    {
+      remove_widgets (window,
+                      priv->extension_box_start,
+                      priv->extension_box_end,
+                      header_widgets);
+    }
+
+  g_list_free (header_widgets);
+}
+
+static void
+plugin_loaded (GtdWindow      *window,
+               gpointer        unused_field,
+               GtdActivatable *activatable)
+{
+  GtdWindowPrivate *priv = gtd_window_get_instance_private (window);
+  gboolean active;
+
+  g_object_get (activatable,
+                "active", &active,
+                NULL);
+
+  if (active)
+    {
+      GList *header_widgets;
+
+      header_widgets = gtd_activatable_get_header_widgets (activatable);
+
+      add_widgets (window,
+                   priv->extension_box_start,
+                   priv->extension_box_end,
+                   header_widgets);
+
+      g_list_free (header_widgets);
+    }
+
+  g_signal_connect (activatable,
+                    "notify::active",
+                    G_CALLBACK (on_active_change),
+                    window);
+}
+
+static void
+plugin_unloaded (GtdWindow      *window,
+                 gpointer        unused_field,
+                 GtdActivatable *activatable)
+{
+  GtdWindowPrivate *priv = gtd_window_get_instance_private (window);
+  gboolean active;
+
+  g_object_get (activatable,
+                "active", &active,
+                NULL);
+
+  if (active)
+    {
+      GList *header_widgets;
+
+      header_widgets = gtd_activatable_get_header_widgets (activatable);
+
+      remove_widgets (window,
+                      priv->extension_box_start,
+                      priv->extension_box_end,
+                      header_widgets);
+    }
+
+  g_signal_handlers_disconnect_by_func (activatable,
+                                        on_active_change,
+                                        window);
+}
+
+static void
 update_panel_menu (GtdWindow *window)
 {
   GtdWindowPrivate *priv = gtd_window_get_instance_private (window);
@@ -321,7 +496,6 @@ gtd_window__stack_visible_child_cb (GtdWindow  *window,
   GtkWidget *visible_child;
   GtdPanel *panel;
   GList *header_widgets;
-  GList *l;
 
   priv = gtd_window_get_instance_private (window);
   visible_child = gtk_stack_get_visible_child (stack);
@@ -337,8 +511,10 @@ gtd_window__stack_visible_child_cb (GtdWindow  *window,
                                             gtd_window__panel_menu_changed,
                                             window);
 
-      for (l = header_widgets; l != NULL; l = l->next)
-        gtk_container_remove (GTK_CONTAINER (priv->headerbar), l->data);
+      remove_widgets (window,
+                      priv->panel_box_start,
+                      priv->panel_box_end,
+                      header_widgets);
 
       g_list_free (header_widgets);
     }
@@ -346,29 +522,10 @@ gtd_window__stack_visible_child_cb (GtdWindow  *window,
   /* Add current panel's header widgets */
   header_widgets = gtd_panel_get_header_widgets (panel);
 
-  for (l = header_widgets; l != NULL; l = l->next)
-    {
-      switch (gtk_widget_get_halign (l->data))
-        {
-        case GTK_ALIGN_START:
-          gtk_header_bar_pack_start (priv->headerbar, l->data);
-          break;
-
-        case GTK_ALIGN_CENTER:
-          gtk_header_bar_set_custom_title (priv->headerbar, l->data);
-          break;
-
-        case GTK_ALIGN_END:
-          gtk_header_bar_pack_end (priv->headerbar, l->data);
-          break;
-
-        case GTK_ALIGN_BASELINE:
-        case GTK_ALIGN_FILL:
-        default:
-          gtk_header_bar_pack_start (priv->headerbar, l->data);
-          break;
-        }
-    }
+  add_widgets (window,
+               priv->panel_box_start,
+               priv->panel_box_end,
+               header_widgets);
 
   g_list_free (header_widgets);
 
@@ -583,6 +740,30 @@ gtd_window_set_property (GObject      *object,
     case PROP_MANAGER:
       self->priv->manager = g_value_get_object (value);
 
+      /* Add plugins' header widgets, and setup for new plugins */
+      {
+        GtdPluginManager *plugin_manager;
+        GList *plugins;
+
+        plugin_manager = gtd_manager_get_plugin_manager (self->priv->manager);
+        plugins = gtd_plugin_manager_get_loaded_plugins (plugin_manager);
+
+        for (l = plugins; l != NULL; l = l->next)
+          plugin_loaded (self, NULL, l->data);
+
+        g_signal_connect_swapped (plugin_manager,
+                                  "plugin-loaded",
+                                  G_CALLBACK (plugin_loaded),
+                                  self);
+
+        g_signal_connect_swapped (plugin_manager,
+                                  "plugin-unloaded",
+                                  G_CALLBACK (plugin_unloaded),
+                                  self);
+
+        g_list_free (plugins);
+      }
+
       g_signal_connect (self->priv->manager,
                         "notify::ready",
                         G_CALLBACK (gtd_window__manager_ready_changed),
@@ -677,6 +858,11 @@ gtd_window_class_init (GtdWindowClass *klass)
   gtk_widget_class_bind_template_child_private (widget_class, GtdWindow, stack);
   gtk_widget_class_bind_template_child_private (widget_class, GtdWindow, stack_switcher);
 
+  gtk_widget_class_bind_template_child_private (widget_class, GtdWindow, extension_box_end);
+  gtk_widget_class_bind_template_child_private (widget_class, GtdWindow, extension_box_start);
+  gtk_widget_class_bind_template_child_private (widget_class, GtdWindow, panel_box_end);
+  gtk_widget_class_bind_template_child_private (widget_class, GtdWindow, panel_box_start);
+
   gtk_widget_class_bind_template_callback (widget_class, gtd_window__cancel_selection_button_clicked);
   gtk_widget_class_bind_template_callback (widget_class, gtd_window__stack_visible_child_cb);
 }
diff --git a/src/interfaces/gtd-activatable.c b/src/interfaces/gtd-activatable.c
index f14c567..1be8016 100644
--- a/src/interfaces/gtd-activatable.c
+++ b/src/interfaces/gtd-activatable.c
@@ -180,6 +180,23 @@ gtd_activatable_default_init (GtdActivatableInterface *iface)
 }
 
 /**
+ * gtd_activatable_get_header_widgets:
+ * @activatable: a #GtdActivatable
+ *
+ * Retrieve the list header widgets of @activatable if any.
+ *
+ * Returns: (transfer container) (element-type #GtkWidget): a #GList
+ */
+GList*
+gtd_activatable_get_header_widgets (GtdActivatable *activatable)
+{
+  g_return_val_if_fail (GTD_IS_ACTIVATABLE (activatable), NULL);
+  g_return_val_if_fail (GTD_ACTIVATABLE_GET_IFACE (activatable)->get_header_widgets, NULL);
+
+  return GTD_ACTIVATABLE_GET_IFACE (activatable)->get_header_widgets (activatable);
+}
+
+/**
  * gtd_activatable_get_preferences_panel:
  * @activatable: a #GtdActivatable
  *
diff --git a/src/interfaces/gtd-activatable.h b/src/interfaces/gtd-activatable.h
index b7f45e1..a017dd3 100644
--- a/src/interfaces/gtd-activatable.h
+++ b/src/interfaces/gtd-activatable.h
@@ -33,6 +33,8 @@ struct _GtdActivatableInterface
 {
   PeasActivatableInterface parent;
 
+  GList*           (*get_header_widgets)                   (GtdActivatable     *activatable);
+
   GtkWidget*       (*get_preferences_panel)                (GtdActivatable     *activatable);
 
   GList*           (*get_panels)                           (GtdActivatable     *activatable);
@@ -40,6 +42,8 @@ struct _GtdActivatableInterface
   GList*           (*get_providers)                        (GtdActivatable     *activatable);
 };
 
+GList*               gtd_activatable_get_header_widgets          (GtdActivatable     *activatable);
+
 GtkWidget*           gtd_activatable_get_preferences_panel       (GtdActivatable     *activatable);
 
 GList*               gtd_activatable_get_panels                  (GtdActivatable     *activatable);


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