[gnome-builder/wip/gtk4-port] plugins/symbol-tree: port symbol scope to GTK 4



commit babfe9292ba816976ae6ea060c7d0b2bd4a536af
Author: Christian Hergert <chergert redhat com>
Date:   Thu Apr 21 15:24:56 2022 -0700

    plugins/symbol-tree: port symbol scope to GTK 4
    
    This also moves the symbol-tree position to the statusbar of the
    workspace rather than in the header of the frame. That might make things
    easier for us to transition to tabs by default, as it gets one more thing
    out of the frame header.
    
    There is still more to do here, such as port the symbol tree to a
    GtkListView and place it in a popover w/ search.

 src/plugins/meson.build                            |   2 +-
 src/plugins/symbol-tree/gbp-symbol-frame-addin.c   | 572 ---------------------
 .../symbol-tree/gbp-symbol-hover-provider.c        |  94 ++--
 src/plugins/symbol-tree/gbp-symbol-menu-button.c   | 330 ------------
 src/plugins/symbol-tree/gbp-symbol-menu-button.h   |  37 --
 src/plugins/symbol-tree/gbp-symbol-menu-button.ui  |  86 ----
 src/plugins/symbol-tree/gbp-symbol-tree-builder.c  | 263 ----------
 src/plugins/symbol-tree/gbp-symbol-util.c          | 163 ++++++
 ...gbp-symbol-tree-builder.h => gbp-symbol-util.h} |  19 +-
 .../symbol-tree/gbp-symbol-workspace-addin.c       | 312 +++++++++++
 ...-frame-addin.h => gbp-symbol-workspace-addin.h} |  10 +-
 src/plugins/symbol-tree/meson.build                |   5 +-
 src/plugins/symbol-tree/symbol-tree-plugin.c       |  15 +-
 src/plugins/symbol-tree/symbol-tree.gresource.xml  |   2 -
 src/plugins/symbol-tree/symbol-tree.plugin         |   5 +-
 src/plugins/symbol-tree/themes/shared.css          |  20 -
 16 files changed, 555 insertions(+), 1380 deletions(-)
---
diff --git a/src/plugins/meson.build b/src/plugins/meson.build
index 84223c8d2..f9341c86e 100644
--- a/src/plugins/meson.build
+++ b/src/plugins/meson.build
@@ -122,7 +122,7 @@ subdir('spellcheck')
 subdir('stylelint')
 #subdir('sublime')
 subdir('support')
-#subdir('symbol-tree')
+subdir('symbol-tree')
 #subdir('sysprof')
 subdir('sysroot')
 subdir('terminal')
diff --git a/src/plugins/symbol-tree/gbp-symbol-hover-provider.c 
b/src/plugins/symbol-tree/gbp-symbol-hover-provider.c
index 75f06c190..3b1dd96ea 100644
--- a/src/plugins/symbol-tree/gbp-symbol-hover-provider.c
+++ b/src/plugins/symbol-tree/gbp-symbol-hover-provider.c
@@ -22,10 +22,11 @@
 
 #include "config.h"
 
+#include <glib/gi18n.h>
+
 #include <libide-code.h>
 #include <libide-gui.h>
 #include <libide-editor.h>
-#include <glib/gi18n.h>
 
 #include "gbp-symbol-hover-provider.h"
 
@@ -41,8 +42,8 @@ on_activate_link (GtkLabel    *label,
                   const gchar *uristr,
                   IdeLocation *location)
 {
+  g_autoptr(IdePanelPosition) position = NULL;
   IdeWorkspace *workspace;
-  IdeSurface *surface;
 
   g_assert (uristr != NULL);
   g_assert (GTK_IS_LABEL (label));
@@ -51,10 +52,8 @@ on_activate_link (GtkLabel    *label,
   if (!(workspace = ide_widget_get_workspace (GTK_WIDGET (label))))
     return FALSE;
 
-  if (!(surface = ide_workspace_get_surface_by_name (workspace, "editor")))
-    return FALSE;
-
-  ide_editor_surface_focus_location (IDE_EDITOR_SURFACE (surface), location);
+  position = ide_panel_position_new ();
+  ide_editor_focus_location (workspace, position, location);
 
   return TRUE;
 }
@@ -69,9 +68,9 @@ gbp_symbol_hover_provider_get_symbol_cb (GObject      *object,
   g_autoptr(IdeSymbol) symbol = NULL;
   g_autoptr(GError) error = NULL;
   g_autofree gchar *tt = NULL;
-  IdeHoverContext *context;
+  GtkSourceHoverDisplay *display;
   const gchar *name;
-  GtkWidget *box;
+  GtkBox *box;
   struct {
     const gchar *kind;
     IdeLocation *loc;
@@ -90,16 +89,19 @@ gbp_symbol_hover_provider_get_symbol_cb (GObject      *object,
       return;
     }
 
-  context = ide_task_get_task_data (task);
-  g_assert (context != NULL);
-  g_assert (IDE_IS_HOVER_CONTEXT (context));
+  display = ide_task_get_task_data (task);
+  g_assert (display != NULL);
+  g_assert (GTK_SOURCE_IS_HOVER_DISPLAY (display));
 
   loc[0].loc = ide_symbol_get_location (symbol);
   loc[1].loc = ide_symbol_get_header_location (symbol);
 
   if (!loc[0].loc && !loc[1].loc)
     {
-      ide_task_return_boolean (task, TRUE);
+      ide_task_return_new_error (task,
+                                 G_IO_ERROR,
+                                 G_IO_ERROR_NOT_SUPPORTED,
+                                 "Not supported");
       return;
     }
 
@@ -113,16 +115,17 @@ gbp_symbol_hover_provider_get_symbol_cb (GObject      *object,
     name = _("Unnamed Symbol");
 
   tt = g_strdup_printf ("<tt><span size='smaller'>%s</span></tt>", name);
-  gtk_container_add (GTK_CONTAINER (box),
-                     g_object_new (GTK_TYPE_LABEL,
-                                   "ellipsize", PANGO_ELLIPSIZE_END,
-                                   "visible", TRUE,
-                                   "xalign", 0.0f,
-                                   "margin-bottom", 3,
-                                   "selectable", TRUE,
-                                   "use-markup", TRUE,
-                                   "label", tt,
-                                   NULL));
+
+  gtk_box_append (box,
+                  g_object_new (GTK_TYPE_LABEL,
+                                "ellipsize", PANGO_ELLIPSIZE_END,
+                                "visible", TRUE,
+                                "xalign", 0.0f,
+                                "margin-bottom", 3,
+                                "selectable", TRUE,
+                                "use-markup", TRUE,
+                                "label", tt,
+                                NULL));
 
 
   for (guint i = 0; i < G_N_ELEMENTS (loc); i++)
@@ -147,47 +150,52 @@ gbp_symbol_hover_provider_get_symbol_cb (GObject      *object,
                                  g_object_ref (loc[i].loc),
                                  (GClosureNotify)g_object_unref,
                                  0);
-          gtk_container_add (GTK_CONTAINER (box), label);
+          gtk_box_append (box, label);
         }
+
     }
 
-  ide_hover_context_add_widget (context, SYMBOL_TREE_HOVER_PRIORITY, _("Symbol"), box);
+  gtk_source_hover_display_append (display, GTK_WIDGET (box));
+
   ide_task_return_boolean (task, TRUE);
 }
 
 static void
-gbp_symbol_hover_provider_hover_async (IdeHoverProvider    *provider,
-                                       IdeHoverContext     *context,
-                                       const GtkTextIter   *iter,
-                                       GCancellable        *cancellable,
-                                       GAsyncReadyCallback  callback,
-                                       gpointer             user_data)
+gbp_symbol_hover_provider_populate_async (GtkSourceHoverProvider *provider,
+                                          GtkSourceHoverContext  *context,
+                                          GtkSourceHoverDisplay  *display,
+                                          GCancellable           *cancellable,
+                                          GAsyncReadyCallback     callback,
+                                          gpointer                user_data)
 {
   GbpSymbolHoverProvider *self = (GbpSymbolHoverProvider *)provider;
   g_autoptr(IdeTask) task = NULL;
+  GtkTextIter iter;
   IdeBuffer *buffer;
 
   g_assert (GBP_IS_SYMBOL_HOVER_PROVIDER (self));
-  g_assert (IDE_IS_HOVER_CONTEXT (context));
-  g_assert (iter != NULL);
+  g_assert (GTK_SOURCE_IS_HOVER_CONTEXT (context));
+  g_assert (GTK_SOURCE_IS_HOVER_DISPLAY (display));
   g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
 
   task = ide_task_new (self, cancellable, callback, user_data);
-  ide_task_set_source_tag (task, gbp_symbol_hover_provider_hover_async);
-  ide_task_set_task_data (task, g_object_ref (context), g_object_unref);
+  ide_task_set_source_tag (task, gbp_symbol_hover_provider_populate_async);
+  ide_task_set_task_data (task, g_object_ref (display), g_object_unref);
+
+  gtk_source_hover_context_get_iter (context, &iter);
+  buffer = IDE_BUFFER (gtk_source_hover_context_get_buffer (context));
 
-  buffer = IDE_BUFFER (gtk_text_iter_get_buffer (iter));
   ide_buffer_get_symbol_at_location_async (buffer,
-                                           iter,
+                                           &iter,
                                            cancellable,
                                            gbp_symbol_hover_provider_get_symbol_cb,
                                            g_steal_pointer (&task));
 }
 
 static gboolean
-gbp_symbol_hover_provider_hover_finish (IdeHoverProvider  *provider,
-                                        GAsyncResult      *result,
-                                        GError           **error)
+gbp_symbol_hover_provider_populate_finish (GtkSourceHoverProvider  *provider,
+                                           GAsyncResult            *result,
+                                           GError                 **error)
 {
   g_assert (GBP_IS_SYMBOL_HOVER_PROVIDER (provider));
   g_assert (IDE_IS_TASK (result));
@@ -196,14 +204,14 @@ gbp_symbol_hover_provider_hover_finish (IdeHoverProvider  *provider,
 }
 
 static void
-hover_provider_iface_init (IdeHoverProviderInterface *iface)
+hover_provider_iface_init (GtkSourceHoverProviderInterface *iface)
 {
-  iface->hover_async = gbp_symbol_hover_provider_hover_async;
-  iface->hover_finish = gbp_symbol_hover_provider_hover_finish;
+  iface->populate_async = gbp_symbol_hover_provider_populate_async;
+  iface->populate_finish = gbp_symbol_hover_provider_populate_finish;
 }
 
 G_DEFINE_FINAL_TYPE_WITH_CODE (GbpSymbolHoverProvider, gbp_symbol_hover_provider, G_TYPE_OBJECT,
-                         G_IMPLEMENT_INTERFACE (IDE_TYPE_HOVER_PROVIDER, hover_provider_iface_init))
+                               G_IMPLEMENT_INTERFACE (GTK_SOURCE_TYPE_HOVER_PROVIDER, 
hover_provider_iface_init))
 
 static void
 gbp_symbol_hover_provider_class_init (GbpSymbolHoverProviderClass *klass)
diff --git a/src/plugins/symbol-tree/gbp-symbol-util.c b/src/plugins/symbol-tree/gbp-symbol-util.c
new file mode 100644
index 000000000..9ca113a58
--- /dev/null
+++ b/src/plugins/symbol-tree/gbp-symbol-util.c
@@ -0,0 +1,163 @@
+/* gbp-symbol-util.c
+ *
+ * Copyright 2022 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/>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#define G_LOG_DOMAIN "gbp-symbol-util"
+
+#include "config.h"
+
+#include <libide-threading.h>
+
+#include "gbp-symbol-util.h"
+
+typedef struct
+{
+  GPtrArray   *resolvers;
+  IdeBuffer   *buffer;
+  IdeLocation *location;
+} FindNearestScope;
+
+static void
+find_nearest_scope_free (FindNearestScope *data)
+{
+  g_assert (data != NULL);
+  g_assert (data->resolvers != NULL);
+  g_assert (data->buffer != NULL);
+  g_assert (IDE_IS_BUFFER (data->buffer));
+  g_assert (IDE_IS_LOCATION (data->location));
+
+  g_clear_pointer (&data->resolvers, g_ptr_array_unref);
+  g_clear_pointer (&data->buffer, ide_buffer_release);
+  g_clear_object (&data->location);
+  g_slice_free (FindNearestScope, data);
+}
+
+static void
+gbp_symbol_find_nearest_scope_cb (GObject      *object,
+                                  GAsyncResult *result,
+                                  gpointer      user_data)
+{
+  IdeSymbolResolver *resolver = (IdeSymbolResolver *)object;
+  g_autoptr(IdeTask) task = user_data;
+  g_autoptr(IdeSymbol) symbol = NULL;
+  g_autoptr(GError) error = NULL;
+  FindNearestScope *data;
+
+  IDE_ENTRY;
+
+  g_assert (IDE_IS_SYMBOL_RESOLVER (resolver));
+  g_assert (G_IS_ASYNC_RESULT (result));
+  g_assert (IDE_IS_TASK (task));
+
+  if ((symbol = ide_symbol_resolver_find_nearest_scope_finish (resolver, result, &error)))
+    {
+      ide_task_return_object (task, g_steal_pointer (&symbol));
+      IDE_EXIT;
+    }
+
+  data = ide_task_get_task_data (task);
+
+  g_assert (data != NULL);
+  g_assert (data->resolvers != NULL);
+  g_assert (data->resolvers->len > 0);
+  g_assert (IDE_IS_LOCATION (data->location));
+  g_assert (IDE_IS_BUFFER (data->buffer));
+
+  g_ptr_array_remove_index (data->resolvers,
+                            data->resolvers->len - 1);
+
+  if (data->resolvers->len == 0)
+    {
+      ide_task_return_new_error (task,
+                                 G_IO_ERROR,
+                                 G_IO_ERROR_NOT_SUPPORTED,
+                                 "No resolvers could locate the nearest scope");
+      IDE_EXIT;
+    }
+
+  ide_symbol_resolver_find_nearest_scope_async (g_ptr_array_index (data->resolvers, data->resolvers->len - 
1),
+                                                data->location,
+                                                ide_task_get_cancellable (task),
+                                                gbp_symbol_find_nearest_scope_cb,
+                                                g_object_ref (task));
+
+  IDE_EXIT;
+}
+
+void
+gbp_symbol_find_nearest_scope_async (IdeBuffer           *buffer,
+                                     GCancellable        *cancellable,
+                                     GAsyncReadyCallback  callback,
+                                     gpointer             user_data)
+{
+  g_autoptr(IdeTask) task = NULL;
+  g_autoptr(GPtrArray) resolvers = NULL;
+  FindNearestScope *data;
+
+  IDE_ENTRY;
+
+  g_return_if_fail (IDE_IS_BUFFER (buffer));
+  g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));
+
+  task = ide_task_new (buffer, cancellable, callback, user_data);
+  ide_task_set_source_tag (task, gbp_symbol_find_nearest_scope_async);
+
+  resolvers = ide_buffer_get_symbol_resolvers (buffer);
+  IDE_PTR_ARRAY_SET_FREE_FUNC (resolvers, g_object_unref);
+
+  if (resolvers == NULL || resolvers->len == 0)
+    {
+      ide_task_return_new_error (task,
+                                 G_IO_ERROR,
+                                 G_IO_ERROR_NOT_SUPPORTED,
+                                 "No symbol resolvers available");
+      IDE_EXIT;
+    }
+
+  data = g_slice_new0 (FindNearestScope);
+  data->resolvers = g_steal_pointer (&resolvers);
+  data->buffer = ide_buffer_hold (buffer);
+  data->location = ide_buffer_get_insert_location (buffer);
+  ide_task_set_task_data (task, data, find_nearest_scope_free);
+
+  ide_symbol_resolver_find_nearest_scope_async (g_ptr_array_index (data->resolvers, data->resolvers->len - 
1),
+                                                data->location,
+                                                cancellable,
+                                                gbp_symbol_find_nearest_scope_cb,
+                                                g_steal_pointer (&task));
+
+  IDE_EXIT;
+}
+
+IdeSymbol *
+gbp_symbol_find_nearest_scope_finish (IdeBuffer     *buffer,
+                                      GAsyncResult  *result,
+                                      GError       **error)
+{
+  IdeSymbol *ret;
+
+  IDE_ENTRY;
+
+  g_return_val_if_fail (IDE_IS_BUFFER (buffer), NULL);
+  g_return_val_if_fail (IDE_IS_TASK (result), NULL);
+
+  ret = ide_task_propagate_object (IDE_TASK (result), error);
+
+  IDE_RETURN (ret);
+}
diff --git a/src/plugins/symbol-tree/gbp-symbol-tree-builder.h b/src/plugins/symbol-tree/gbp-symbol-util.h
similarity index 52%
rename from src/plugins/symbol-tree/gbp-symbol-tree-builder.h
rename to src/plugins/symbol-tree/gbp-symbol-util.h
index f999f822c..32d8e9c2a 100644
--- a/src/plugins/symbol-tree/gbp-symbol-tree-builder.h
+++ b/src/plugins/symbol-tree/gbp-symbol-util.h
@@ -1,6 +1,6 @@
-/* gbp-symbol-tree-builder.h
+/* gbp-symbol-util.h
  *
- * Copyright 2015-2019 Christian Hergert <christian hergert me>
+ * Copyright 2022 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
@@ -20,15 +20,16 @@
 
 #pragma once
 
-#include <libide-gui.h>
+#include <libide-code.h>
 
 G_BEGIN_DECLS
 
-#define GBP_TYPE_SYMBOL_TREE_BUILDER (gbp_symbol_tree_builder_get_type())
-
-G_DECLARE_FINAL_TYPE (GbpSymbolTreeBuilder, gbp_symbol_tree_builder, GBP, SYMBOL_TREE_BUILDER, 
DzlTreeBuilder)
-
-void gbp_symbol_tree_builder_set_filter (GbpSymbolTreeBuilder *self,
-                                         const gchar          *filter);
+void       gbp_symbol_find_nearest_scope_async  (IdeBuffer            *buffer,
+                                                 GCancellable         *cancellable,
+                                                 GAsyncReadyCallback   callback,
+                                                 gpointer              user_data);
+IdeSymbol *gbp_symbol_find_nearest_scope_finish (IdeBuffer            *buffer,
+                                                 GAsyncResult         *result,
+                                                 GError              **error);
 
 G_END_DECLS
diff --git a/src/plugins/symbol-tree/gbp-symbol-workspace-addin.c 
b/src/plugins/symbol-tree/gbp-symbol-workspace-addin.c
new file mode 100644
index 000000000..dca47d2f8
--- /dev/null
+++ b/src/plugins/symbol-tree/gbp-symbol-workspace-addin.c
@@ -0,0 +1,312 @@
+/* gbp-symbol-workspace-addin.c
+ *
+ * Copyright 2022 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/>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#define G_LOG_DOMAIN "gbp-symbol-workspace-addin"
+
+#include "config.h"
+
+#include <glib/gi18n.h>
+
+#include <libide-code.h>
+#include <libide-editor.h>
+#include <libide-gui.h>
+
+#include "gbp-symbol-workspace-addin.h"
+#include "gbp-symbol-util.h"
+
+#define RELOAD_DELAY_MSEC 150
+
+struct _GbpSymbolWorkspaceAddin
+{
+  GObject         parent_instance;
+
+  IdeWorkspace   *workspace;
+  PanelStatusbar *statusbar;
+
+  GtkMenuButton  *menu_button;
+  GtkLabel       *menu_label;
+  GtkImage       *menu_image;
+
+  IdeSignalGroup *buffer_signals;
+  guint           reload_timeout_source;
+};
+
+static void
+gbp_symbol_workspace_addin_set_symbol (GbpSymbolWorkspaceAddin *self,
+                                       IdeSymbol               *symbol)
+{
+  const char *label;
+  const char *icon_name;
+
+  IDE_ENTRY;
+
+  g_assert (GBP_IS_SYMBOL_WORKSPACE_ADDIN (self));
+  g_assert (!symbol || IDE_IS_SYMBOL (symbol));
+
+  if (symbol == NULL)
+    {
+      gtk_label_set_label (self->menu_label, _("Select Symbol…"));
+      gtk_image_set_from_icon_name (self->menu_image, NULL);
+      gtk_widget_hide (GTK_WIDGET (self->menu_image));
+      IDE_EXIT;
+    }
+
+  label = ide_symbol_get_name (symbol);
+  icon_name = ide_symbol_kind_get_icon_name (ide_symbol_get_kind (symbol));
+
+  gtk_label_set_label (self->menu_label, label);
+  gtk_image_set_from_icon_name (self->menu_image, icon_name);
+  gtk_widget_set_visible (GTK_WIDGET (self->menu_image), icon_name != NULL);
+
+  IDE_EXIT;
+}
+
+static void
+gbp_symbol_workspace_addin_get_symbol_cb (GObject      *object,
+                                          GAsyncResult *result,
+                                          gpointer      user_data)
+{
+  IdeBuffer *buffer = (IdeBuffer *)object;
+  g_autoptr(GbpSymbolWorkspaceAddin) self = user_data;
+  g_autoptr(IdeSymbol) symbol = NULL;
+  g_autoptr(GError) error = NULL;
+
+  IDE_ENTRY;
+
+  g_assert (IDE_IS_BUFFER (buffer));
+  g_assert (G_IS_ASYNC_RESULT (result));
+  g_assert (GBP_IS_SYMBOL_WORKSPACE_ADDIN (self));
+
+  if (!(symbol = gbp_symbol_find_nearest_scope_finish (buffer, result, &error)))
+    {
+      if (!ide_error_ignore (error))
+        g_warning ("Failed to get symbol at location: %s", error->message);
+      IDE_GOTO (failure);
+    }
+
+  if ((gpointer)buffer != ide_signal_group_get_target (self->buffer_signals))
+    IDE_GOTO (failure);
+
+  gbp_symbol_workspace_addin_set_symbol (self, symbol);
+  gtk_widget_show (GTK_WIDGET (self->menu_button));
+
+  IDE_EXIT;
+
+failure:
+
+  /* Raced against another query and lost, just bail */
+  if (ide_signal_group_get_target (self->buffer_signals) != buffer)
+    IDE_EXIT;
+
+  gbp_symbol_workspace_addin_set_symbol (self, NULL);
+  gtk_widget_show (GTK_WIDGET (self->menu_button));
+
+  IDE_EXIT;
+}
+
+static void
+gbp_symbol_workspace_addin_update (GbpSymbolWorkspaceAddin *self,
+                                   IdeBuffer               *buffer)
+{
+  IDE_ENTRY;
+
+  g_assert (GBP_IS_SYMBOL_WORKSPACE_ADDIN (self));
+  g_assert (IDE_IS_BUFFER (buffer));
+
+  if (!ide_buffer_has_symbol_resolvers (buffer))
+    {
+      gbp_symbol_workspace_addin_set_symbol (self, NULL);
+      gtk_widget_hide (GTK_WIDGET (self->menu_button));
+      IDE_EXIT;
+    }
+
+  gbp_symbol_find_nearest_scope_async (buffer,
+                                       NULL,
+                                       gbp_symbol_workspace_addin_get_symbol_cb,
+                                       g_object_ref (self));
+
+  IDE_EXIT;
+}
+
+static void
+gbp_symbol_workspace_addin_buffer_bind_cb (GbpSymbolWorkspaceAddin *self,
+                                           IdeBuffer               *buffer,
+                                           IdeSignalGroup          *signal_group)
+{
+  g_assert (GBP_IS_SYMBOL_WORKSPACE_ADDIN (self));
+  g_assert (IDE_IS_BUFFER (buffer));
+  g_assert (IDE_IS_SIGNAL_GROUP (signal_group));
+
+  gbp_symbol_workspace_addin_update (self, buffer);
+}
+
+static gboolean
+gbp_symbol_workspace_addin_reload_timeout (gpointer data)
+{
+  GbpSymbolWorkspaceAddin *self = data;
+  IdeBuffer *buffer;
+
+  IDE_ENTRY;
+
+  g_assert (GBP_IS_SYMBOL_WORKSPACE_ADDIN (self));
+
+  self->reload_timeout_source = 0;
+
+  if ((buffer = ide_signal_group_get_target (self->buffer_signals)))
+    gbp_symbol_workspace_addin_update (self, buffer);
+  else
+    gtk_widget_hide (GTK_WIDGET (self->menu_button));
+
+  IDE_RETURN (G_SOURCE_REMOVE);
+}
+
+static void
+gbp_symbol_workspace_addin_buffer_cursor_moved_cb (GbpSymbolWorkspaceAddin *self,
+                                                   IdeBuffer               *buffer)
+{
+  g_assert (GBP_IS_SYMBOL_WORKSPACE_ADDIN (self));
+  g_assert (IDE_IS_BUFFER (buffer));
+
+  if (self->reload_timeout_source == 0)
+    self->reload_timeout_source = g_timeout_add (RELOAD_DELAY_MSEC,
+                                                 gbp_symbol_workspace_addin_reload_timeout,
+                                                 self);
+}
+
+static void
+gbp_symbol_workspace_addin_load (IdeWorkspaceAddin *addin,
+                                 IdeWorkspace      *workspace)
+{
+  GbpSymbolWorkspaceAddin *self = (GbpSymbolWorkspaceAddin *)addin;
+  GtkBox *box;
+
+  IDE_ENTRY;
+
+  g_assert (GBP_IS_SYMBOL_WORKSPACE_ADDIN (self));
+  g_assert (IDE_IS_WORKSPACE (workspace));
+
+  self->workspace = workspace;
+  self->statusbar = ide_workspace_get_statusbar (workspace);
+
+  self->buffer_signals = ide_signal_group_new (IDE_TYPE_BUFFER);
+  g_signal_connect_object (self->buffer_signals,
+                           "bind",
+                           G_CALLBACK (gbp_symbol_workspace_addin_buffer_bind_cb),
+                           self,
+                           G_CONNECT_SWAPPED);
+  ide_signal_group_connect_object (self->buffer_signals,
+                                   "cursor-moved",
+                                   G_CALLBACK (gbp_symbol_workspace_addin_buffer_cursor_moved_cb),
+                                   self,
+                                   G_CONNECT_SWAPPED);
+
+  box = g_object_new (GTK_TYPE_BOX,
+                      "orientation", GTK_ORIENTATION_HORIZONTAL,
+                      "spacing", 6,
+                      NULL);
+  self->menu_image = g_object_new (GTK_TYPE_IMAGE,
+                                   "icon-name", "lang-function-symbolic",
+                                   NULL);
+  gtk_box_append (box, GTK_WIDGET (self->menu_image));
+  self->menu_label = g_object_new (GTK_TYPE_LABEL,
+                                   "label", _("Select Symbol…"),
+                                   "xalign", 0.0f,
+                                   "ellipsize", PANGO_ELLIPSIZE_END,
+                                   NULL);
+  gtk_box_append (box, GTK_WIDGET (self->menu_label));
+  self->menu_button = g_object_new (GTK_TYPE_MENU_BUTTON,
+                                    "child", box,
+                                    "visible", FALSE,
+                                    NULL);
+
+  panel_statusbar_add_suffix (self->statusbar, 20000, GTK_WIDGET (self->menu_button));
+
+  IDE_EXIT;
+}
+
+static void
+gbp_symbol_workspace_addin_unload (IdeWorkspaceAddin *addin,
+                                   IdeWorkspace      *workspace)
+{
+  GbpSymbolWorkspaceAddin *self = (GbpSymbolWorkspaceAddin *)addin;
+
+  IDE_ENTRY;
+
+  g_assert (GBP_IS_SYMBOL_WORKSPACE_ADDIN (self));
+  g_assert (IDE_IS_WORKSPACE (workspace));
+  g_assert (PANEL_IS_STATUSBAR (self->statusbar));
+  g_assert (workspace == self->workspace);
+
+  g_clear_object (&self->buffer_signals);
+  g_clear_handle_id (&self->reload_timeout_source, g_source_remove);
+  panel_statusbar_remove (self->statusbar, GTK_WIDGET (self->menu_button));
+
+  self->menu_button = NULL;
+  self->menu_label = NULL;
+  self->menu_image = NULL;
+  self->workspace = NULL;
+  self->statusbar = NULL;
+
+  IDE_EXIT;
+}
+
+static void
+gbp_symbol_workspace_addin_page_changed (IdeWorkspaceAddin *addin,
+                                         IdePage           *page)
+{
+  GbpSymbolWorkspaceAddin *self = (GbpSymbolWorkspaceAddin *)addin;
+  IdeBuffer *buffer = NULL;
+
+  IDE_ENTRY;
+
+  g_assert (GBP_IS_SYMBOL_WORKSPACE_ADDIN (self));
+  g_assert (!page || IDE_IS_PAGE (page));
+
+  gbp_symbol_workspace_addin_set_symbol (self, NULL);
+  gtk_widget_hide (GTK_WIDGET (self->menu_button));
+
+  if (IDE_IS_EDITOR_PAGE (page))
+    buffer = ide_editor_page_get_buffer (IDE_EDITOR_PAGE (page));
+
+  ide_signal_group_set_target (self->buffer_signals, buffer);
+
+  IDE_EXIT;
+}
+
+static void
+workspace_addin_iface_init (IdeWorkspaceAddinInterface *iface)
+{
+  iface->load = gbp_symbol_workspace_addin_load;
+  iface->unload = gbp_symbol_workspace_addin_unload;
+  iface->page_changed = gbp_symbol_workspace_addin_page_changed;
+}
+
+G_DEFINE_FINAL_TYPE_WITH_CODE (GbpSymbolWorkspaceAddin, gbp_symbol_workspace_addin, G_TYPE_OBJECT,
+                               G_IMPLEMENT_INTERFACE (IDE_TYPE_WORKSPACE_ADDIN, workspace_addin_iface_init))
+
+static void
+gbp_symbol_workspace_addin_class_init (GbpSymbolWorkspaceAddinClass *klass)
+{
+}
+
+static void
+gbp_symbol_workspace_addin_init (GbpSymbolWorkspaceAddin *self)
+{
+}
diff --git a/src/plugins/symbol-tree/gbp-symbol-frame-addin.h 
b/src/plugins/symbol-tree/gbp-symbol-workspace-addin.h
similarity index 70%
rename from src/plugins/symbol-tree/gbp-symbol-frame-addin.h
rename to src/plugins/symbol-tree/gbp-symbol-workspace-addin.h
index db160ac53..e0cd9e580 100644
--- a/src/plugins/symbol-tree/gbp-symbol-frame-addin.h
+++ b/src/plugins/symbol-tree/gbp-symbol-workspace-addin.h
@@ -1,6 +1,6 @@
-/* gbp-symbol-frame-addin.h
+/* gbp-symbol-workspace-addin.h
  *
- * Copyright 2017-2019 Christian Hergert <chergert redhat com>
+ * Copyright 2022 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
@@ -20,12 +20,12 @@
 
 #pragma once
 
-#include <libide-gui.h>
+#include <glib-object.h>
 
 G_BEGIN_DECLS
 
-#define GBP_TYPE_SYMBOL_FRAME_ADDIN (gbp_symbol_frame_addin_get_type())
+#define GBP_TYPE_SYMBOL_WORKSPACE_ADDIN (gbp_symbol_workspace_addin_get_type())
 
-G_DECLARE_FINAL_TYPE (GbpSymbolFrameAddin, gbp_symbol_frame_addin, GBP, SYMBOL_FRAME_ADDIN, GObject)
+G_DECLARE_FINAL_TYPE (GbpSymbolWorkspaceAddin, gbp_symbol_workspace_addin, GBP, SYMBOL_WORKSPACE_ADDIN, 
GObject)
 
 G_END_DECLS
diff --git a/src/plugins/symbol-tree/meson.build b/src/plugins/symbol-tree/meson.build
index 1eeb61f54..9e6d6819d 100644
--- a/src/plugins/symbol-tree/meson.build
+++ b/src/plugins/symbol-tree/meson.build
@@ -1,8 +1,7 @@
 plugins_sources += files([
   'gbp-symbol-hover-provider.c',
-  'gbp-symbol-frame-addin.c',
-  'gbp-symbol-menu-button.c',
-  'gbp-symbol-tree-builder.c',
+  'gbp-symbol-util.c',
+  'gbp-symbol-workspace-addin.c',
   'symbol-tree-plugin.c',
 ])
 
diff --git a/src/plugins/symbol-tree/symbol-tree-plugin.c b/src/plugins/symbol-tree/symbol-tree-plugin.c
index 0408a034e..b641650a3 100644
--- a/src/plugins/symbol-tree/symbol-tree-plugin.c
+++ b/src/plugins/symbol-tree/symbol-tree-plugin.c
@@ -1,6 +1,6 @@
 /* symbol-tree-plugin.c
  *
- * Copyright 2017-2019 Christian Hergert <chergert redhat com>
+ * Copyright 2017-2022 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
@@ -21,19 +21,20 @@
 #include "config.h"
 
 #include <libpeas/peas.h>
-#include <libide-sourceview.h>
+
 #include <libide-gui.h>
+#include <libide-sourceview.h>
 
-#include "gbp-symbol-frame-addin.h"
 #include "gbp-symbol-hover-provider.h"
+#include "gbp-symbol-workspace-addin.h"
 
 _IDE_EXTERN void
 _gbp_symbol_tree_register_types (PeasObjectModule *module)
 {
   peas_object_module_register_extension_type (module,
-                                              IDE_TYPE_FRAME_ADDIN,
-                                              GBP_TYPE_SYMBOL_FRAME_ADDIN);
-  peas_object_module_register_extension_type (module,
-                                              IDE_TYPE_HOVER_PROVIDER,
+                                              GTK_SOURCE_TYPE_HOVER_PROVIDER,
                                               GBP_TYPE_SYMBOL_HOVER_PROVIDER);
+  peas_object_module_register_extension_type (module,
+                                              IDE_TYPE_WORKSPACE_ADDIN,
+                                              GBP_TYPE_SYMBOL_WORKSPACE_ADDIN);
 }
diff --git a/src/plugins/symbol-tree/symbol-tree.gresource.xml 
b/src/plugins/symbol-tree/symbol-tree.gresource.xml
index 44bbb417c..f2c33673c 100644
--- a/src/plugins/symbol-tree/symbol-tree.gresource.xml
+++ b/src/plugins/symbol-tree/symbol-tree.gresource.xml
@@ -2,7 +2,5 @@
 <gresources>
   <gresource prefix="/plugins/symbol-tree">
     <file>symbol-tree.plugin</file>
-    <file>gbp-symbol-menu-button.ui</file>
-    <file>themes/shared.css</file>
   </gresource>
 </gresources>
diff --git a/src/plugins/symbol-tree/symbol-tree.plugin b/src/plugins/symbol-tree/symbol-tree.plugin
index 1f667252f..923746413 100644
--- a/src/plugins/symbol-tree/symbol-tree.plugin
+++ b/src/plugins/symbol-tree/symbol-tree.plugin
@@ -1,9 +1,10 @@
 [Plugin]
 Authors=Christian Hergert <christian hergert me>
 Builtin=true
-Copyright=Copyright © 2015-2018 Christian Hergert
+Copyright=Copyright © 2015-2022 Christian Hergert
 Description=Provides a Symbol Tree for the currently focused document
 Embedded=_gbp_symbol_tree_register_types
-Hidden=true
 Module=symbol-tree
 Name=Symbol Tree
+X-Category=editing
+X-Workspace-Kind=primary;editor;


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