[gnome-builder] greeter: add IdeGreeterSection pluggable API



commit a6d60d30dac9e10ad159af548b5c3c10a4e497d9
Author: Christian Hergert <chergert redhat com>
Date:   Fri Nov 17 14:43:15 2017 -0800

    greeter: add IdeGreeterSection pluggable API
    
    This adds a new IdeGreeterSection interface to be used for
    defining sections in the primary greeter. As part of this, the
    newcomers section has been removed from libide and will come
    back as a plugin.
    
    Additionally, we should be able to remove the recent projects
    section from libide and move that to a plugin. That is not part
    of this refactoring and can happen at some point in the future,
    as it is fairly low priority.

 src/libide/greeter/icons/org.gnome.Calendar.png |  Bin 197273 -> 0 bytes
 src/libide/greeter/icons/org.gnome.Games.png    |  Bin 173231 -> 0 bytes
 src/libide/greeter/icons/org.gnome.Maps.png     |  Bin 43685 -> 0 bytes
 src/libide/greeter/icons/org.gnome.Music.png    |  Bin 93983 -> 0 bytes
 src/libide/greeter/icons/org.gnome.Nautilus.png |  Bin 60905 -> 0 bytes
 src/libide/greeter/icons/org.gnome.Photos.png   |  Bin 60258 -> 0 bytes
 src/libide/greeter/icons/org.gnome.Polari.png   |  Bin 42950 -> 0 bytes
 src/libide/greeter/icons/org.gnome.Todo.png     |  Bin 85334 -> 0 bytes
 src/libide/greeter/ide-greeter-perspective.c    |  415 +++++++++++++----------
 src/libide/greeter/ide-greeter-perspective.ui   |  101 +------
 src/libide/greeter/ide-greeter-section.c        |  104 ++++++
 src/libide/greeter/ide-greeter-section.h        |   53 +++
 src/libide/greeter/ide-newcomer-project.c       |  164 ---------
 src/libide/greeter/ide-newcomer-project.h       |   33 --
 src/libide/greeter/ide-newcomer-project.ui      |   27 --
 src/libide/greeter/meson.build                  |    4 +-
 src/libide/ide.h                                |    1 +
 src/libide/libide.gresource.xml                 |   13 -
 18 files changed, 398 insertions(+), 517 deletions(-)
---
diff --git a/src/libide/greeter/ide-greeter-perspective.c b/src/libide/greeter/ide-greeter-perspective.c
index daa7f82..f102f6b 100644
--- a/src/libide/greeter/ide-greeter-perspective.c
+++ b/src/libide/greeter/ide-greeter-perspective.c
@@ -29,7 +29,7 @@
 #include "genesis/ide-genesis-addin.h"
 #include "greeter/ide-greeter-perspective.h"
 #include "greeter/ide-greeter-project-row.h"
-#include "greeter/ide-newcomer-project.h"
+#include "greeter/ide-greeter-section.h"
 #include "util/ide-gtk.h"
 #include "workbench/ide-perspective.h"
 #include "workbench/ide-workbench-private.h"
@@ -47,6 +47,8 @@ struct _IdeGreeterPerspective
   GBinding             *ready_binding;
   GCancellable         *cancellable;
 
+  PeasExtensionSet     *sections;
+
   GtkStack             *stack;
   GtkStack             *top_stack;
   GtkButton            *genesis_continue_button;
@@ -67,13 +69,22 @@ struct _IdeGreeterPerspective
   DzlStateMachine      *state_machine;
   GtkScrolledWindow    *scrolled_window;
   DzlPriorityBox       *genesis_buttons;
-  GtkFlowBox           *newcomer_projects;
+  DzlPriorityBox       *sections_container;
 
   gint                  selected_count;
 };
 
-static void ide_perspective_iface_init (IdePerspectiveInterface *iface);
-static void ide_greeter_perspective_genesis_continue (IdeGreeterPerspective *self);
+typedef struct
+{
+  IdeGreeterPerspective *self;
+  IdeVcsUri             *vcs_uri;
+  gboolean               handled;
+} LoadProject;
+
+static void     ide_perspective_iface_init               (IdePerspectiveInterface *iface);
+static void     ide_greeter_perspective_genesis_continue (IdeGreeterPerspective   *self);
+static gboolean ide_greeter_perspective_load_project     (IdeGreeterPerspective   *self,
+                                                          IdeProjectInfo          *project_info);
 
 G_DEFINE_TYPE_EXTENDED (IdeGreeterPerspective, ide_greeter_perspective, GTK_TYPE_BIN, 0,
                         G_IMPLEMENT_INTERFACE (IDE_TYPE_PERSPECTIVE,
@@ -177,6 +188,23 @@ ide_greeter_perspective_apply_filter (IdeGreeterPerspective *self,
 }
 
 static void
+ide_greeter_perspective_filter_sections (PeasExtensionSet *set,
+                                         PeasPluginInfo   *plugin_info,
+                                         PeasExtension    *exten,
+                                         gpointer          user_data)
+{
+  IdeGreeterPerspective *self = user_data;
+  IdeGreeterSection *section = (IdeGreeterSection *)exten;
+
+  g_assert (PEAS_IS_EXTENSION_SET (set));
+  g_assert (plugin_info != NULL);
+  g_assert (IDE_IS_GREETER_SECTION (section));
+  g_assert (IDE_IS_GREETER_PERSPECTIVE (self));
+
+  ide_greeter_section_filter (section, self->pattern_spec);
+}
+
+static void
 ide_greeter_perspective_apply_filter_all (IdeGreeterPerspective *self)
 {
   const gchar *text;
@@ -190,6 +218,11 @@ ide_greeter_perspective_apply_filter_all (IdeGreeterPerspective *self)
   ide_greeter_perspective_apply_filter (self,
                                         self->my_projects_list_box,
                                         GTK_WIDGET (self->my_projects_container));
+
+  if (self->sections != NULL)
+    peas_extension_set_foreach (self->sections,
+                                ide_greeter_perspective_filter_sections,
+                                self);
 }
 
 static void
@@ -454,62 +487,24 @@ ide_greeter_perspective__row_activated (IdeGreeterPerspective *self,
                                         GtkListBox            *list_box)
 {
   IdeProjectInfo *project_info;
-  IdeWorkbench *workbench = NULL;
-  GFile *project_file;
-  GList *list;
-  GtkWindow *window;
-  IdeContext *context;
 
   g_assert (IDE_IS_GREETER_PERSPECTIVE (self));
   g_assert (IDE_IS_GREETER_PROJECT_ROW (row));
   g_assert (GTK_IS_LIST_BOX (list_box));
 
-  if (ide_str_equal0 (dzl_state_machine_get_state (self->state_machine), "selection"))
+  if (dzl_state_machine_is_state (self->state_machine, "selection"))
     {
       gboolean selected = FALSE;
 
       g_object_get (row, "selected", &selected, NULL);
       g_object_set (row, "selected", !selected, NULL);
+
       return;
     }
 
   project_info = ide_greeter_project_row_get_project_info (row);
-  project_file = ide_project_info_get_file (project_info);
-
-  gtk_widget_set_sensitive (GTK_WIDGET (self), FALSE);
-  gtk_widget_set_sensitive (GTK_WIDGET (self->titlebar), FALSE);
-
-  workbench = ide_widget_get_workbench (GTK_WIDGET (self));
-
-  list = gtk_application_get_windows (gtk_window_get_application (GTK_WINDOW (workbench)));
-
-  for (; list != NULL; list = list->next)
-    {
-      window = list->data;
-      context = ide_workbench_get_context (IDE_WORKBENCH (window));
-
-      if (context != NULL)
-        {
-          if (g_file_equal (ide_context_get_project_file (context), project_file))
-            {
-              gtk_window_present (window);
-              gtk_window_close (GTK_WINDOW (workbench));
-              workbench = NULL;
-              break;
-            }
-        }
-    }
-
-  if(workbench != NULL)
-    {
-      ide_workbench_open_project_async (workbench,
-                                        project_file,
-                                        NULL,
-                                        ide_greeter_perspective_open_project_cb,
-                                        g_object_ref (self));
-    }
 
-  ide_project_info_set_is_recent (project_info, TRUE);
+  ide_greeter_perspective_load_project (self, project_info);
 }
 
 static gboolean
@@ -1069,43 +1064,6 @@ ide_greeter_perspective_info_bar_response (IdeGreeterPerspective *self,
   gtk_revealer_set_reveal_child (self->info_bar_revealer, FALSE);
 }
 
-static void
-ide_greeter_perspective_maybe_clone (PeasExtensionSet *set,
-                                     PeasPluginInfo   *plugin_info,
-                                     PeasExtension    *exten,
-                                     gpointer          user_data)
-{
-  IdeGenesisAddin *addin = (IdeGenesisAddin *)exten;
-  struct {
-    IdeGreeterPerspective *self;
-    IdeVcsUri *uri;
-    gboolean found;
-  } *lookup = user_data;
-
-  g_assert (PEAS_IS_EXTENSION_SET (set));
-  g_assert (plugin_info != NULL);
-  g_assert (IDE_IS_GENESIS_ADDIN (addin));
-  g_assert (lookup != NULL);
-
-  if (lookup->found)
-    return;
-
-  lookup->found = ide_genesis_addin_apply_uri (addin, lookup->uri);
-
-  if (lookup->found)
-    {
-      GtkWidget *child = ide_genesis_addin_get_widget (addin);
-
-      if (child != NULL)
-        {
-          gtk_stack_set_visible_child (lookup->self->genesis_stack, child);
-          dzl_state_machine_set_state (lookup->self->state_machine, "genesis");
-          gtk_widget_hide (GTK_WIDGET (lookup->self->genesis_continue_button));
-          ide_greeter_perspective_genesis_continue (lookup->self);
-        }
-    }
-}
-
 static gchar *
 get_project_directory (const gchar *name)
 {
@@ -1122,130 +1080,222 @@ get_project_directory (const gchar *name)
 }
 
 static void
-ide_greeter_perspective_open_cb (GObject      *object,
-                                 GAsyncResult *result,
-                                 gpointer      user_data)
+ide_greeter_perspective_load_project_cb (PeasExtensionSet *set,
+                                         PeasPluginInfo   *plugin_info,
+                                         PeasExtension    *exten,
+                                         gpointer          user_data)
 {
-  IdeWorkbench *workbench = (IdeWorkbench *)object;
-  g_autoptr(IdeGreeterPerspective) self = user_data;
-
-  g_assert (IDE_IS_GREETER_PERSPECTIVE (self));
-  g_assert (G_IS_ASYNC_RESULT (result));
-
-  if (!ide_workbench_open_project_finish (workbench, result, NULL))
-    gtk_widget_set_sensitive (GTK_WIDGET (self), TRUE);
-}
+  IdeGenesisAddin *addin = (IdeGenesisAddin *)exten;
+  LoadProject *load = user_data;
 
-static void
-ide_greeter_perspective_do_open (IdeGreeterPerspective *self,
-                                 const gchar           *path)
-{
-  g_autoptr(GFile) file = NULL;
-  IdeWorkbench *workbench;
+  g_assert (PEAS_IS_EXTENSION_SET (set));
+  g_assert (plugin_info != NULL);
+  g_assert (IDE_IS_GENESIS_ADDIN (addin));
+  g_assert (load != NULL);
+  g_assert (IDE_IS_GREETER_PERSPECTIVE (load->self));
+  g_assert (load->vcs_uri != NULL);
 
-  g_assert (IDE_IS_GREETER_PERSPECTIVE (self));
-  g_assert (path != NULL);
+  if (load->handled)
+    return;
 
-  file = g_file_new_for_path (path);
-  workbench = ide_widget_get_workbench (GTK_WIDGET (self));
+  load->handled = ide_genesis_addin_apply_uri (addin, load->vcs_uri);
 
-  gtk_widget_set_sensitive (GTK_WIDGET (self), FALSE);
+  if (load->handled)
+    {
+      GtkWidget *child = ide_genesis_addin_get_widget (addin);
 
-  ide_workbench_open_project_async (workbench,
-                                    file,
-                                    NULL,
-                                    ide_greeter_perspective_open_cb,
-                                    g_object_ref (self));
+      if (child != NULL)
+        {
+          gtk_stack_set_visible_child (load->self->genesis_stack, child);
+          dzl_state_machine_set_state (load->self->state_machine, "genesis");
+          gtk_widget_hide (GTK_WIDGET (load->self->genesis_continue_button));
+          ide_greeter_perspective_genesis_continue (load->self);
+        }
+    }
 }
 
 static gboolean
 ide_greeter_perspective_load_project (IdeGreeterPerspective *self,
-                                      IdeNewcomerProject    *project)
+                                      IdeProjectInfo        *project_info)
 {
-  g_autofree gchar *dir = NULL;
-  g_autofree gchar *maybe_project = NULL;
-  g_autofree gchar *relocated = NULL;
-  IdeRecentProjects *projects;
-  const gchar *path;
-  const gchar *str;
-  IdeVcsUri *uri;
+  IdeWorkbench *workbench;
+  IdeVcsUri *vcs_uri;
+  GFile *project_file;
 
-  g_assert (IDE_IS_GREETER_PERSPECTIVE (self));
-  g_assert (IDE_IS_NEWCOMER_PROJECT (project));
+  IDE_ENTRY;
 
-  projects = ide_application_get_recent_projects (IDE_APPLICATION_DEFAULT);
-  str = ide_newcomer_project_get_uri (project);
-  uri = ide_vcs_uri_new (str);
-  path = ide_vcs_uri_get_path (uri);
-  dir = g_path_get_basename (path);
+  g_assert (IDE_IS_GREETER_PERSPECTIVE (self));
+  g_assert (IDE_IS_PROJECT_INFO (project_info));
 
-  if (g_str_has_suffix (dir, ".git"))
-    dir[strlen (dir) - 4] = '\0';
+  workbench = ide_widget_get_workbench (GTK_WIDGET (self));
 
-  maybe_project = get_project_directory (dir);
-  relocated = ide_recent_projects_find_by_directory (projects, maybe_project);
+  /* Mark this project info as having been selected */
+  ide_project_info_set_is_recent (project_info, TRUE);
 
-  if (relocated != NULL)
+  /* If the project info has a project file, open that. */
+  if (NULL != (project_file = ide_project_info_get_file (project_info)))
     {
-      ide_greeter_perspective_do_open (self, relocated);
-      return TRUE;
+      gtk_widget_set_sensitive (GTK_WIDGET (self), FALSE);
+      gtk_widget_set_sensitive (GTK_WIDGET (self->titlebar), FALSE);
+      ide_workbench_open_project_async (workbench,
+                                        project_file,
+                                        NULL,
+                                        ide_greeter_perspective_open_project_cb,
+                                        g_object_ref (self));
+      IDE_RETURN (TRUE);
     }
 
-  /* If the test exists, we probably should just open that
-   * instead of trying to reclone, which would fail anyway since
-   * this directory already exists.
+  /*
+   * If this project info has a uri, we might be able to find it already
+   * checked out on the system.
    */
-  if (g_file_test (maybe_project, G_FILE_TEST_IS_DIR))
+  if (NULL != (vcs_uri = ide_project_info_get_vcs_uri (project_info)))
     {
-      ide_greeter_perspective_do_open (self, maybe_project);
-      return TRUE;
+      LoadProject load = { 0 };
+      const gchar *path;
+
+      if (NULL != (path = ide_vcs_uri_get_path (vcs_uri)))
+        {
+          IdeApplication *app = IDE_APPLICATION_DEFAULT;
+          IdeRecentProjects *projects = ide_application_get_recent_projects (app);
+          g_autofree gchar *dir = NULL;
+          g_autofree gchar *maybe_project = NULL;
+          g_autofree gchar *relocated = NULL;
+          const gchar *previous = NULL;
+
+          dir = g_path_get_basename (path);
+
+          /* XXX: Would be nice if this could be abstracted */
+          if (g_str_has_suffix (dir, ".git"))
+            dir[strlen (dir) - 4] = '\0';
+
+          maybe_project = get_project_directory (dir);
+
+          /*
+           * We might find the project already cloned (using our simple check
+           * for the directory name), or possibly from our recent projects.
+           */
+          if (g_file_test (maybe_project, G_FILE_TEST_IS_DIR))
+            previous = maybe_project;
+          else
+            previous = relocated = ide_recent_projects_find_by_directory (projects, maybe_project);
+
+          if (previous != NULL)
+            {
+              g_autoptr(GFile) file = g_file_new_for_path (previous);
+
+              gtk_widget_set_sensitive (GTK_WIDGET (self), FALSE);
+              gtk_widget_set_sensitive (GTK_WIDGET (self->titlebar), FALSE);
+              ide_workbench_open_project_async (workbench,
+                                                file,
+                                                NULL,
+                                                ide_greeter_perspective_open_project_cb,
+                                                g_object_ref (self));
+              IDE_RETURN (TRUE);
+            }
+        }
+
+      /*
+       * Okay, we didn't handle this, see if one of the genesis plugins
+       * knows how to handle the given vcs uri.
+       */
+
+      load.self = self;
+      load.vcs_uri = vcs_uri;
+      load.handled = FALSE;
+
+      peas_extension_set_foreach (self->genesis_set,
+                                  ide_greeter_perspective_load_project_cb,
+                                  &load);
+
+      if (load.handled)
+        IDE_RETURN (TRUE);
     }
 
-  return FALSE;
+  /*
+   * TODO: Failed to locate something that could open this project.
+   *       Notify the user of the error and continue.
+   */
+
+  IDE_RETURN (FALSE);
 }
 
 static void
-ide_greeter_perspective__newcomer_activated (IdeGreeterPerspective *self,
-                                             GtkFlowBoxChild       *child,
-                                             GtkFlowBox            *flow_box)
+ide_greeter_perspective_project_activated (IdeGreeterPerspective *self,
+                                           IdeProjectInfo        *project_info,
+                                           IdeGreeterSection     *section)
 {
-  g_autoptr(IdeVcsUri) vcs_uri = NULL;
-  IdeNewcomerProject *project;
-  const gchar *uri;
-  struct {
-    IdeGreeterPerspective *self;
-    IdeVcsUri *uri;
-    gboolean found;
-  } lookup;
+  IDE_ENTRY;
+
+  g_assert (IDE_IS_GREETER_PERSPECTIVE (self));
+  g_assert (IDE_IS_PROJECT_INFO (project_info));
+  g_assert (IDE_IS_GREETER_SECTION (section));
+
+  ide_greeter_perspective_load_project (self, project_info);
+
+  IDE_EXIT;
+}
+
+static void
+ide_greeter_perspective_section_added (PeasExtensionSet *set,
+                                       PeasPluginInfo   *plugin_info,
+                                       PeasExtension    *exten,
+                                       gpointer          user_data)
+{
+  IdeGreeterPerspective *self = user_data;
+  IdeGreeterSection *section = (IdeGreeterSection *)exten;
+  gint priority;
 
   IDE_ENTRY;
 
+  g_return_if_fail (PEAS_IS_EXTENSION_SET (set));
+  g_return_if_fail (plugin_info != NULL);
   g_return_if_fail (IDE_IS_GREETER_PERSPECTIVE (self));
-  g_return_if_fail (GTK_IS_FLOW_BOX_CHILD (child));
-  g_return_if_fail (GTK_IS_FLOW_BOX (flow_box));
+  g_return_if_fail (IDE_IS_GREETER_SECTION (section));
 
-  project = IDE_NEWCOMER_PROJECT (gtk_bin_get_child (GTK_BIN (child)));
+  /* Take the floating GtkWidget reference */
+  if (g_object_is_floating (section))
+    g_object_ref_sink (section);
 
-  /* Try to reload the project if they've already opened
-   * this one before. Look at our recent projects and if not
-   * there, the Projects directory for a matching project
-   * directory name from the uri.
-   */
-  if (ide_greeter_perspective_load_project (self, project))
-    IDE_EXIT;
+  g_signal_connect_object (section,
+                           "project-activated",
+                           G_CALLBACK (ide_greeter_perspective_project_activated),
+                           self,
+                           G_CONNECT_SWAPPED);
+
+  /* Add the section to our box with priority */
+  priority = ide_greeter_section_get_priority (section);
+  gtk_container_add_with_properties (GTK_CONTAINER (self->sections_container),
+                                     GTK_WIDGET (section),
+                                     "priority", priority,
+                                     NULL);
+  gtk_widget_show (GTK_WIDGET (section));
 
-  uri = ide_newcomer_project_get_uri (project);
-  vcs_uri = ide_vcs_uri_new (uri);
+  IDE_EXIT;
+}
 
-  IDE_TRACE_MSG ("Looking for genesis addin to handle %s", uri);
+static void
+ide_greeter_perspective_section_removed (PeasExtensionSet *set,
+                                         PeasPluginInfo   *plugin_info,
+                                         PeasExtension    *exten,
+                                         gpointer          user_data)
+{
+  IdeGreeterPerspective *self = user_data;
+  IdeGreeterSection *section = (IdeGreeterSection *)exten;
 
-  lookup.self = self;
-  lookup.uri = vcs_uri;
-  lookup.found = FALSE;
+  IDE_ENTRY;
 
-  peas_extension_set_foreach (self->genesis_set,
-                              ide_greeter_perspective_maybe_clone,
-                              &lookup);
+  g_return_if_fail (PEAS_IS_EXTENSION_SET (set));
+  g_return_if_fail (plugin_info != NULL);
+  g_return_if_fail (IDE_IS_GREETER_PERSPECTIVE (self));
+  g_return_if_fail (IDE_IS_GREETER_SECTION (section));
+
+  g_signal_handlers_disconnect_by_func (section,
+                                        G_CALLBACK (ide_greeter_perspective_project_activated),
+                                        self);
+
+  gtk_container_remove (GTK_CONTAINER (self->sections_container),
+                        GTK_WIDGET (section));
 
   IDE_EXIT;
 }
@@ -1262,6 +1312,21 @@ ide_greeter_perspective_constructed (GObject *object)
   ide_greeter_perspective_set_recent_projects (self, recent_projects);
 
   ide_greeter_perspective_load_genesis_addins (self);
+
+  self->sections = peas_extension_set_new (peas_engine_get_default (),
+                                           IDE_TYPE_GREETER_SECTION,
+                                           NULL);
+  g_signal_connect (self->sections,
+                    "extension-added",
+                    G_CALLBACK (ide_greeter_perspective_section_added),
+                    self);
+  g_signal_connect (self->sections,
+                    "extension-removed",
+                    G_CALLBACK (ide_greeter_perspective_section_removed),
+                    self);
+  peas_extension_set_foreach (self->sections,
+                              ide_greeter_perspective_section_added,
+                              self);
 }
 
 static void
@@ -1272,6 +1337,8 @@ ide_greeter_perspective_destroy (GtkWidget *widget)
   if (self->titlebar != NULL)
     gtk_widget_destroy (GTK_WIDGET (self->titlebar));
 
+  g_clear_object (&self->sections);
+
   GTK_WIDGET_CLASS (ide_greeter_perspective_parent_class)->destroy (widget);
 }
 
@@ -1362,18 +1429,16 @@ ide_greeter_perspective_class_init (IdeGreeterPerspectiveClass *klass)
   gtk_widget_class_bind_template_child (widget_class, IdeGreeterPerspective, info_bar_revealer);
   gtk_widget_class_bind_template_child (widget_class, IdeGreeterPerspective, my_projects_container);
   gtk_widget_class_bind_template_child (widget_class, IdeGreeterPerspective, my_projects_list_box);
-  gtk_widget_class_bind_template_child (widget_class, IdeGreeterPerspective, newcomer_projects);
   gtk_widget_class_bind_template_child (widget_class, IdeGreeterPerspective, open_button);
   gtk_widget_class_bind_template_child (widget_class, IdeGreeterPerspective, remove_button);
   gtk_widget_class_bind_template_child (widget_class, IdeGreeterPerspective, scrolled_window);
   gtk_widget_class_bind_template_child (widget_class, IdeGreeterPerspective, search_entry);
+  gtk_widget_class_bind_template_child (widget_class, IdeGreeterPerspective, sections_container);
   gtk_widget_class_bind_template_child (widget_class, IdeGreeterPerspective, stack);
   gtk_widget_class_bind_template_child (widget_class, IdeGreeterPerspective, state_machine);
   gtk_widget_class_bind_template_child (widget_class, IdeGreeterPerspective, titlebar);
   gtk_widget_class_bind_template_child (widget_class, IdeGreeterPerspective, top_stack);
   gtk_widget_class_bind_template_child (widget_class, IdeGreeterPerspective, viewport);
-
-  g_type_ensure (IDE_TYPE_NEWCOMER_PROJECT);
 }
 
 static const GActionEntry actions[] = {
@@ -1424,12 +1489,6 @@ ide_greeter_perspective_init (IdeGreeterPerspective *self)
                            self,
                            G_CONNECT_SWAPPED);
 
-  g_signal_connect_object (self->newcomer_projects,
-                           "child-activated",
-                           G_CALLBACK (ide_greeter_perspective__newcomer_activated),
-                           self,
-                           G_CONNECT_SWAPPED);
-
   g_signal_connect_object (self->top_stack,
                            "notify::visible-child",
                            G_CALLBACK (ide_greeter_perspective_genesis_changed),
diff --git a/src/libide/greeter/ide-greeter-perspective.ui b/src/libide/greeter/ide-greeter-perspective.ui
index 445cbf3..3411887 100644
--- a/src/libide/greeter/ide-greeter-perspective.ui
+++ b/src/libide/greeter/ide-greeter-perspective.ui
@@ -71,7 +71,7 @@
                                 <property name="expand">true</property>
                                 <property name="visible">true</property>
                                 <child>
-                                  <object class="GtkBox">
+                                  <object class="DzlPriorityBox" id="sections_container">
                                     <property name="orientation">vertical</property>
                                     <property name="spacing">32</property>
                                     <property name="visible">true</property>
@@ -143,99 +143,6 @@
                                         </child>
                                       </object>
                                     </child>
-                                    <child>
-                                      <object class="GtkBox" id="newcomer_container">
-                                        <property name="orientation">vertical</property>
-                                        <property name="spacing">6</property>
-                                        <property name="visible">true</property>
-                                        <child>
-                                          <object class="GtkLabel">
-                                            <property name="label" translatable="yes">Newcomer 
Projects</property>
-                                            <property name="visible">true</property>
-                                            <style>
-                                              <class name="dim-label"/>
-                                            </style>
-                                            <attributes>
-                                              <attribute name="weight" value="bold"/>
-                                            </attributes>
-                                          </object>
-                                        </child>
-                                        <child>
-                                          <object class="GtkFlowBox" id="newcomer_projects">
-                                            <property name="visible">true</property>
-                                            <property name="halign">center</property>
-                                            <property name="valign">start</property>
-                                            <property name="selection-mode">browse</property>
-                                            <property name="min-children-per-line">3</property>
-                                            <property name="max-children-per-line">5</property>
-                                            <child>
-                                              <object class="IdeNewcomerProject">
-                                                <property name="name" translatable="yes">Polari</property>
-                                                <property name="icon-name">org.gnome.Polari</property>
-                                                <property 
name="uri">https://gitlab.gnome.org/GNOME/polari.git</property>
-                                                <property name="visible">true</property>
-                                              </object>
-                                            </child>
-                                            <child>
-                                              <object class="IdeNewcomerProject">
-                                                <property name="name" translatable="yes">Games</property>
-                                                <property name="icon-name">org.gnome.Games</property>
-                                                <property 
name="uri">https://git.gnome.org/browse/gnome-games</property>
-                                                <property name="visible">true</property>
-                                              </object>
-                                            </child>
-                                            <child>
-                                              <object class="IdeNewcomerProject">
-                                                <property name="name" translatable="yes">Maps</property>
-                                                <property name="icon-name">org.gnome.Maps</property>
-                                                <property 
name="uri">https://git.gnome.org/browse/gnome-maps</property>
-                                                <property name="visible">true</property>
-                                              </object>
-                                            </child>
-                                            <child>
-                                              <object class="IdeNewcomerProject">
-                                                <property name="name" translatable="yes">Todo</property>
-                                                <property name="icon-name">org.gnome.Todo</property>
-                                                <property 
name="uri">https://gitlab.gnome.org/GNOME/gnome-todo.git</property>
-                                                <property name="visible">true</property>
-                                              </object>
-                                            </child>
-                                            <child>
-                                              <object class="IdeNewcomerProject">
-                                                <property name="name" translatable="yes">Music</property>
-                                                <property name="icon-name">org.gnome.Music</property>
-                                                <property 
name="uri">https://git.gnome.org/browse/gnome-music</property>
-                                                <property name="visible">true</property>
-                                              </object>
-                                            </child>
-                                            <child>
-                                              <object class="IdeNewcomerProject">
-                                                <property name="name" translatable="yes">Nautilus</property>
-                                                <property name="icon-name">org.gnome.Nautilus</property>
-                                                <property 
name="uri">https://gitlab.gnome.org/GNOME/nautilus.git</property>
-                                                <property name="visible">true</property>
-                                              </object>
-                                            </child>
-                                            <child>
-                                              <object class="IdeNewcomerProject">
-                                                <property name="name" translatable="yes">Photos</property>
-                                                <property name="icon-name">org.gnome.Photos</property>
-                                                <property 
name="uri">https://git.gnome.org/browse/gnome-photos</property>
-                                                <property name="visible">true</property>
-                                              </object>
-                                            </child>
-                                            <child>
-                                              <object class="IdeNewcomerProject">
-                                                <property name="name" translatable="yes">Calendar</property>
-                                                <property name="icon-name">org.gnome.Calendar</property>
-                                                <property 
name="uri">https://git.gnome.org/browse/gnome-calendar.git</property>
-                                                <property name="visible">true</property>
-                                              </object>
-                                            </child>
-                                          </object>
-                                        </child>
-                                      </object>
-                                    </child>
                                   </object>
                                 </child>
                               </object>
@@ -428,9 +335,6 @@
         <object id="genesis_continue_button">
           <property name="visible">false</property>
         </object>
-        <object id="newcomer_container">
-          <property name="visible">true</property>
-        </object>
         <object id="top_stack">
           <property name="visible-child-name">greeter</property>
         </object>
@@ -466,9 +370,6 @@
         <object id="genesis_continue_button">
           <property name="visible">false</property>
         </object>
-        <object id="newcomer_container">
-          <property name="visible">false</property>
-        </object>
         <object id="top_stack">
           <property name="visible-child-name">greeter</property>
         </object>
diff --git a/src/libide/greeter/ide-greeter-section.c b/src/libide/greeter/ide-greeter-section.c
new file mode 100644
index 0000000..230446a
--- /dev/null
+++ b/src/libide/greeter/ide-greeter-section.c
@@ -0,0 +1,104 @@
+/* ide-greeter-section.c
+ *
+ * Copyright (C) 2017 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-greeter-section"
+
+#include "greeter/ide-greeter-section.h"
+
+G_DEFINE_INTERFACE (IdeGreeterSection, ide_greeter_section, GTK_TYPE_WIDGET)
+
+enum {
+  PROJECT_ACTIVATED,
+  N_SIGNALS
+};
+
+static guint signals [N_SIGNALS];
+
+static void
+ide_greeter_section_default_init (IdeGreeterSectionInterface *iface)
+{
+  /**
+   * IdeGreeterSection::project-activated:
+   *
+   * The "project-activated" signal is emitted when a project has been
+   * selected by the user in the section.
+   *
+   * Use ide_greeter_section_emit_project_activated() to activate
+   * this signal.
+   *
+   * Since: 3.28
+   */
+  signals [PROJECT_ACTIVATED] =
+    g_signal_new ("project-activated",
+                  G_TYPE_FROM_INTERFACE (iface),
+                  G_SIGNAL_RUN_LAST,
+                  G_STRUCT_OFFSET (IdeGreeterSectionInterface, project_activated),
+                  NULL, NULL, NULL,
+                  G_TYPE_NONE, 1, IDE_TYPE_PROJECT_INFO);
+}
+
+/**
+ * ide_greeter_section_get_priority:
+ * @self: an #IdeGreeterSection
+ *
+ * Get the priority of the section. The lowest integral value is
+ * sorted first in the list of sections.
+ *
+ * Returns: the priority for the section
+ *
+ * Since: 3.28
+ */
+gint
+ide_greeter_section_get_priority (IdeGreeterSection *self)
+{
+  g_return_val_if_fail (IDE_IS_GREETER_SECTION (self), 0);
+
+  if (IDE_GREETER_SECTION_GET_IFACE (self)->get_priority)
+    return IDE_GREETER_SECTION_GET_IFACE (self)->get_priority (self);
+
+  return 0;
+}
+
+/**
+ * ide_greeter_section_filter:
+ * @self: a #IdeGreeterSection
+ * @spec: (nullable): a #DzlPatternSpec or %NULL
+ *
+ * Refilter the visibile items based on the current search.
+ *
+ * Since: 3.28
+ */
+void
+ide_greeter_section_filter (IdeGreeterSection *self,
+                            DzlPatternSpec    *spec)
+{
+  g_return_if_fail (IDE_IS_GREETER_SECTION (self));
+
+  if (IDE_GREETER_SECTION_GET_IFACE (self)->filter)
+    IDE_GREETER_SECTION_GET_IFACE (self)->filter (self, spec);
+}
+
+void
+ide_greeter_section_emit_project_activated (IdeGreeterSection *self,
+                                            IdeProjectInfo    *project_info)
+{
+  g_return_if_fail (IDE_IS_GREETER_SECTION (self));
+  g_return_if_fail (IDE_IS_PROJECT_INFO (project_info));
+
+  g_signal_emit (self, signals [PROJECT_ACTIVATED], 0, project_info);
+}
diff --git a/src/libide/greeter/ide-greeter-section.h b/src/libide/greeter/ide-greeter-section.h
new file mode 100644
index 0000000..741e261
--- /dev/null
+++ b/src/libide/greeter/ide-greeter-section.h
@@ -0,0 +1,53 @@
+/* ide-greeter-section.h
+ *
+ * Copyright (C) 2017 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/>.
+ */
+
+#pragma once
+
+#include <dazzle.h>
+
+#include "ide-version-macros.h"
+
+#include "projects/ide-project-info.h"
+
+G_BEGIN_DECLS
+
+#define IDE_TYPE_GREETER_SECTION (ide_greeter_section_get_type ())
+
+G_DECLARE_INTERFACE (IdeGreeterSection, ide_greeter_section, IDE, GREETER_SECTION, GtkWidget)
+
+struct _IdeGreeterSectionInterface
+{
+  GTypeInterface parent_iface;
+
+  void (*project_activated) (IdeGreeterSection *self,
+                             IdeProjectInfo    *project_info);
+  gint (*get_priority)      (IdeGreeterSection *self);
+  void (*filter)            (IdeGreeterSection *self,
+                             DzlPatternSpec    *pattern);
+};
+
+IDE_AVAILABLE_IN_3_28
+gint ide_greeter_section_get_priority           (IdeGreeterSection *self);
+IDE_AVAILABLE_IN_3_28
+void ide_greeter_section_filter                 (IdeGreeterSection *self,
+                                                 DzlPatternSpec    *spec);
+IDE_AVAILABLE_IN_3_28
+void ide_greeter_section_emit_project_activated (IdeGreeterSection *self,
+                                                 IdeProjectInfo    *project_info);
+
+G_END_DECLS
diff --git a/src/libide/greeter/meson.build b/src/libide/greeter/meson.build
index 574db12..594ba66 100644
--- a/src/libide/greeter/meson.build
+++ b/src/libide/greeter/meson.build
@@ -3,8 +3,8 @@ greeter_private_sources = [
   'ide-greeter-perspective.h',
   'ide-greeter-project-row.c',
   'ide-greeter-project-row.h',
-  'ide-newcomer-project.c',
-  'ide-newcomer-project.h',
+  'ide-greeter-section.c',
+  'ide-greeter-section.h',
 ]
 
 libide_private_sources += files(greeter_private_sources)
diff --git a/src/libide/ide.h b/src/libide/ide.h
index 63f7b37..3b94426 100644
--- a/src/libide/ide.h
+++ b/src/libide/ide.h
@@ -101,6 +101,7 @@ G_BEGIN_DECLS
 #include "files/ide-file-settings.h"
 #include "files/ide-file.h"
 #include "genesis/ide-genesis-addin.h"
+#include "greeter/ide-greeter-section.h"
 #include "highlighting/ide-highlight-engine.h"
 #include "highlighting/ide-highlight-index.h"
 #include "highlighting/ide-highlighter.h"
diff --git a/src/libide/libide.gresource.xml b/src/libide/libide.gresource.xml
index ebfe845..c238e6b 100644
--- a/src/libide/libide.gresource.xml
+++ b/src/libide/libide.gresource.xml
@@ -76,7 +76,6 @@
     <file preprocess="xml-stripblanks" alias="ide-editor-view.ui">editor/ide-editor-view.ui</file>
     <file preprocess="xml-stripblanks" 
alias="ide-greeter-perspective.ui">greeter/ide-greeter-perspective.ui</file>
     <file preprocess="xml-stripblanks" 
alias="ide-greeter-project-row.ui">greeter/ide-greeter-project-row.ui</file>
-    <file preprocess="xml-stripblanks" alias="ide-newcomer-project.ui">greeter/ide-newcomer-project.ui</file>
     <file preprocess="xml-stripblanks" alias="ide-omni-bar.ui">workbench/ide-omni-bar.ui</file>
     <file preprocess="xml-stripblanks" 
alias="ide-omni-pausable-row.ui">workbench/ide-omni-pausable-row.ui</file>
     <file preprocess="xml-stripblanks" 
alias="ide-preferences-language-row.ui">preferences/ide-preferences-language-row.ui</file>
@@ -91,18 +90,6 @@
     <file preprocess="xml-stripblanks" 
alias="ide-workbench-message.ui">workbench/ide-workbench-message.ui</file>
   </gresource>
 
-  <!-- Icons used by the greeter for newcomer projects -->
-  <gresource prefix="/org/gnome/builder/icons">
-    <file alias="256x256/apps/org.gnome.Maps.png">greeter/icons/org.gnome.Maps.png</file>
-    <file alias="256x256/apps/org.gnome.Music.png">greeter/icons/org.gnome.Music.png</file>
-    <file alias="256x256/apps/org.gnome.Photos.png">greeter/icons/org.gnome.Photos.png</file>
-    <file alias="512x512/apps/org.gnome.Calendar.png">greeter/icons/org.gnome.Calendar.png</file>
-    <file alias="512x512/apps/org.gnome.Games.png">greeter/icons/org.gnome.Games.png</file>
-    <file alias="512x512/apps/org.gnome.Nautilus.png">greeter/icons/org.gnome.Nautilus.png</file>
-    <file alias="512x512/apps/org.gnome.Polari.png">greeter/icons/org.gnome.Polari.png</file>
-    <file alias="512x512/apps/org.gnome.Todo.png">greeter/icons/org.gnome.Todo.png</file>
-  </gresource>
-
   <gresource prefix="/org/gnome/builder/plugins/buildconfig">
     <file alias="buildconfig.plugin">buildconfig/buildconfig.plugin</file>
   </gresource>



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