[gnome-builder/wip/gtk4-port: 47/94] tree: port IdeTree to GTK 4




commit f526836cd1a53cb77f0f46da762f54df2db3cc02
Author: Christian Hergert <chergert redhat com>
Date:   Fri Sep 24 12:58:13 2021 -0700

    tree: port IdeTree to GTK 4
    
    This still needs some additional work after an initial port.
    
     * Use Icons for Status cell renderer so we get texture caching
     * Make DnD work, which will need drop-target work

 src/libide/tree/ide-cell-renderer-status.c |  44 +++----
 src/libide/tree/ide-tree-addin.c           |  18 +--
 src/libide/tree/ide-tree-addin.h           |  40 +++---
 src/libide/tree/ide-tree-model.c           |  47 ++++---
 src/libide/tree/ide-tree-node.c            |   1 -
 src/libide/tree/ide-tree.c                 | 191 ++++++++++++++++-------------
 src/libide/tree/ide-tree.h                 |  52 ++++----
 7 files changed, 204 insertions(+), 189 deletions(-)
---
diff --git a/src/libide/tree/ide-cell-renderer-status.c b/src/libide/tree/ide-cell-renderer-status.c
index 29bc39e45..ea082a5ad 100644
--- a/src/libide/tree/ide-cell-renderer-status.c
+++ b/src/libide/tree/ide-cell-renderer-status.c
@@ -80,50 +80,50 @@ ide_cell_renderer_status_get_preferred_width (GtkCellRenderer *cell,
 }
 
 static void
-ide_cell_renderer_status_render (GtkCellRenderer      *cell,
-                                 cairo_t              *cr,
-                                 GtkWidget            *widget,
-                                 const GdkRectangle   *bg_area,
-                                 const GdkRectangle   *cell_area,
-                                 GtkCellRendererState  state)
+ide_cell_renderer_status_snapshot (GtkCellRenderer      *cell,
+                                   GtkSnapshot          *snapshot,
+                                   GtkWidget            *widget,
+                                   const GdkRectangle   *bg_area,
+                                   const GdkRectangle   *cell_area,
+                                   GtkCellRendererState  state)
 {
   IdeCellRendererStatus *self = (IdeCellRendererStatus *)cell;
   GtkStyleContext *style_context;
+  cairo_t *cr;
   GdkRGBA color;
 
   g_assert (IDE_IS_CELL_RENDERER_STATUS (self));
-  g_assert (cr != NULL);
   g_assert (GTK_IS_WIDGET (widget));
   g_assert (bg_area != NULL);
   g_assert (cell_area != NULL);
 
+  /* FIXME-GTK4: This should be ported to use symbolic icons instead */
+
   if (self->flags == 0)
     return;
 
   style_context = gtk_widget_get_style_context (widget);
-  gtk_style_context_save (style_context);
-
-  if (state & GTK_CELL_RENDERER_SELECTED)
-    gtk_style_context_set_state (style_context,
-                                 gtk_style_context_get_state (style_context) & GTK_STATE_FLAG_SELECTED);
-  gtk_style_context_get_color (style_context,
-                               gtk_style_context_get_state (style_context),
-                               &color);
-  gdk_cairo_set_source_rgba (cr, &color);
+  gtk_style_context_get_color (style_context, &color);
+
+  cr = gtk_snapshot_append_cairo (snapshot,
+                                  &GRAPHENE_RECT_INIT (cell_area->x,
+                                                       cell_area->y,
+                                                       cell_area->width,
+                                                       cell_area->height));
 
   cairo_arc (cr,
-             cell_area->x + cell_area->width - RPAD - (CELL_WIDTH/2),
-             cell_area->y + (cell_area->height / 2),
+             cell_area->width - RPAD - (CELL_WIDTH/2),
+             (cell_area->height / 2),
              3,
              0,
              M_PI * 2);
 
+  gdk_cairo_set_source_rgba (cr, &color);
   if (self->flags & IDE_TREE_NODE_FLAGS_ADDED)
     cairo_fill_preserve (cr);
-
   cairo_stroke (cr);
 
-  gtk_style_context_restore (style_context);
+  cairo_destroy (cr);
 }
 
 static void
@@ -175,7 +175,7 @@ ide_cell_renderer_status_class_init (IdeCellRendererStatusClass *klass)
 
   renderer_class->get_preferred_height = ide_cell_renderer_status_get_preferred_height;
   renderer_class->get_preferred_width = ide_cell_renderer_status_get_preferred_width;
-  renderer_class->render = ide_cell_renderer_status_render;
+  renderer_class->snapshot = ide_cell_renderer_status_snapshot;
 
   properties [PROP_FLAGS] =
     g_param_spec_uint ("flags",
@@ -183,7 +183,7 @@ ide_cell_renderer_status_class_init (IdeCellRendererStatusClass *klass)
                        "The flags for the state",
                        0, G_MAXUINT, 0,
                        (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-  
+
   g_object_class_install_properties (object_class, N_PROPS, properties);
 }
 
diff --git a/src/libide/tree/ide-tree-addin.c b/src/libide/tree/ide-tree-addin.c
index 973ce7ffa..c8a86731d 100644
--- a/src/libide/tree/ide-tree-addin.c
+++ b/src/libide/tree/ide-tree-addin.c
@@ -67,7 +67,7 @@ static void
 ide_tree_addin_real_node_dropped_async (IdeTreeAddin        *self,
                                         IdeTreeNode         *drag_node,
                                         IdeTreeNode         *drop_node,
-                                        GtkSelectionData    *selection,
+                                        const GValue        *value,
                                         GdkDragAction        actions,
                                         GCancellable        *cancellable,
                                         GAsyncReadyCallback  callback,
@@ -298,17 +298,17 @@ ide_tree_addin_node_draggable (IdeTreeAddin *self,
 }
 
 gboolean
-ide_tree_addin_node_droppable (IdeTreeAddin     *self,
-                               IdeTreeNode      *drag_node,
-                               IdeTreeNode      *drop_node,
-                               GtkSelectionData *selection)
+ide_tree_addin_node_droppable (IdeTreeAddin *self,
+                               IdeTreeNode  *drag_node,
+                               IdeTreeNode  *drop_node,
+                               const GValue *value)
 {
   g_return_val_if_fail (IDE_IS_TREE_ADDIN (self), FALSE);
   g_return_val_if_fail (!drag_node || IDE_IS_TREE_NODE (drag_node), FALSE);
   g_return_val_if_fail (!drop_node || IDE_IS_TREE_NODE (drop_node), FALSE);
 
   if (IDE_TREE_ADDIN_GET_IFACE (self)->node_droppable)
-    return IDE_TREE_ADDIN_GET_IFACE (self)->node_droppable (self, drag_node, drop_node, selection);
+    return IDE_TREE_ADDIN_GET_IFACE (self)->node_droppable (self, drag_node, drop_node, value);
 
   return FALSE;
 }
@@ -317,7 +317,7 @@ void
 ide_tree_addin_node_dropped_async (IdeTreeAddin        *self,
                                    IdeTreeNode         *drag_node,
                                    IdeTreeNode         *drop_node,
-                                   GtkSelectionData    *selection,
+                                   const GValue        *value,
                                    GdkDragAction        actions,
                                    GCancellable        *cancellable,
                                    GAsyncReadyCallback  callback,
@@ -327,13 +327,13 @@ ide_tree_addin_node_dropped_async (IdeTreeAddin        *self,
   g_return_if_fail (IDE_IS_TREE_ADDIN (self));
   g_return_if_fail (!drag_node || IDE_IS_TREE_NODE (drag_node));
   g_return_if_fail (!drop_node || IDE_IS_TREE_NODE (drop_node));
-  g_return_if_fail (selection != NULL);
+  g_return_if_fail (value != NULL);
   g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));
 
   IDE_TREE_ADDIN_GET_IFACE (self)->node_dropped_async (self,
                                                        drag_node,
                                                        drop_node,
-                                                       selection,
+                                                       value,
                                                        actions,
                                                        cancellable,
                                                        callback,
diff --git a/src/libide/tree/ide-tree-addin.h b/src/libide/tree/ide-tree-addin.h
index 92275620d..6dce9936a 100644
--- a/src/libide/tree/ide-tree-addin.h
+++ b/src/libide/tree/ide-tree-addin.h
@@ -28,9 +28,9 @@
 
 G_BEGIN_DECLS
 
-#define IDE_TYPE_TREE_ADDIN (ide_tree_addin_get_type ())
+#define IDE_TYPE_TREE_ADDIN (ide_tree_addin_get_type())
 
-IDE_AVAILABLE_IN_3_32
+IDE_AVAILABLE_IN_ALL
 G_DECLARE_INTERFACE (IdeTreeAddin, ide_tree_addin, IDE, TREE_ADDIN, GObject)
 
 struct _IdeTreeAddinInterface
@@ -72,11 +72,11 @@ struct _IdeTreeAddinInterface
   gboolean (*node_droppable)        (IdeTreeAddin         *self,
                                      IdeTreeNode          *drag_node,
                                      IdeTreeNode          *drop_node,
-                                     GtkSelectionData     *selection);
+                                     const GValue         *value);
   void     (*node_dropped_async)    (IdeTreeAddin         *self,
                                      IdeTreeNode          *drag_node,
                                      IdeTreeNode          *drop_node,
-                                     GtkSelectionData     *selection,
+                                     const GValue         *value,
                                      GdkDragAction         actions,
                                      GCancellable         *cancellable,
                                      GAsyncReadyCallback   callback,
@@ -86,62 +86,62 @@ struct _IdeTreeAddinInterface
                                      GError              **error);
 };
 
-IDE_AVAILABLE_IN_3_32
+IDE_AVAILABLE_IN_ALL
 void     ide_tree_addin_load                  (IdeTreeAddin         *self,
                                                IdeTree              *tree,
                                                IdeTreeModel         *model);
-IDE_AVAILABLE_IN_3_32
+IDE_AVAILABLE_IN_ALL
 void     ide_tree_addin_unload                (IdeTreeAddin         *self,
                                                IdeTree              *tree,
                                                IdeTreeModel         *model);
-IDE_AVAILABLE_IN_3_32
+IDE_AVAILABLE_IN_ALL
 void     ide_tree_addin_build_node            (IdeTreeAddin         *self,
                                                IdeTreeNode          *node);
-IDE_AVAILABLE_IN_3_32
+IDE_AVAILABLE_IN_ALL
 void     ide_tree_addin_build_children_async  (IdeTreeAddin         *self,
                                                IdeTreeNode          *node,
                                                GCancellable         *cancellable,
                                                GAsyncReadyCallback   callback,
                                                gpointer              user_data);
-IDE_AVAILABLE_IN_3_32
+IDE_AVAILABLE_IN_ALL
 gboolean ide_tree_addin_build_children_finish (IdeTreeAddin         *self,
                                                GAsyncResult         *result,
                                                GError              **error);
-IDE_AVAILABLE_IN_3_32
+IDE_AVAILABLE_IN_ALL
 gboolean ide_tree_addin_node_activated        (IdeTreeAddin         *self,
                                                IdeTree              *tree,
                                                IdeTreeNode          *node);
-IDE_AVAILABLE_IN_3_32
+IDE_AVAILABLE_IN_ALL
 void     ide_tree_addin_selection_changed     (IdeTreeAddin         *self,
                                                IdeTreeNode          *selection);
-IDE_AVAILABLE_IN_3_32
+IDE_AVAILABLE_IN_ALL
 void     ide_tree_addin_node_expanded         (IdeTreeAddin         *self,
                                                IdeTreeNode          *node);
-IDE_AVAILABLE_IN_3_32
+IDE_AVAILABLE_IN_ALL
 void     ide_tree_addin_node_collapsed        (IdeTreeAddin         *self,
                                                IdeTreeNode          *node);
-IDE_AVAILABLE_IN_3_32
+IDE_AVAILABLE_IN_ALL
 gboolean ide_tree_addin_node_draggable        (IdeTreeAddin         *self,
                                                IdeTreeNode          *node);
-IDE_AVAILABLE_IN_3_32
+IDE_AVAILABLE_IN_ALL
 gboolean ide_tree_addin_node_droppable        (IdeTreeAddin         *self,
                                                IdeTreeNode          *drag_node,
                                                IdeTreeNode          *drop_node,
-                                               GtkSelectionData     *selection);
-IDE_AVAILABLE_IN_3_32
+                                               const GValue         *value);
+IDE_AVAILABLE_IN_ALL
 void     ide_tree_addin_node_dropped_async    (IdeTreeAddin         *self,
                                                IdeTreeNode          *drag_node,
                                                IdeTreeNode          *drop_node,
-                                               GtkSelectionData     *selection,
+                                               const GValue         *value,
                                                GdkDragAction         actions,
                                                GCancellable         *cancellable,
                                                GAsyncReadyCallback   callback,
                                                gpointer              user_data);
-IDE_AVAILABLE_IN_3_32
+IDE_AVAILABLE_IN_ALL
 gboolean ide_tree_addin_node_dropped_finish   (IdeTreeAddin         *self,
                                                GAsyncResult         *result,
                                                GError              **error);
-IDE_AVAILABLE_IN_3_32
+IDE_AVAILABLE_IN_ALL
 void     ide_tree_addin_cell_data_func        (IdeTreeAddin         *self,
                                                IdeTreeNode          *node,
                                                GtkCellRenderer      *cell);
diff --git a/src/libide/tree/ide-tree-model.c b/src/libide/tree/ide-tree-model.c
index a9318e871..aa6c7e467 100644
--- a/src/libide/tree/ide-tree-model.c
+++ b/src/libide/tree/ide-tree-model.c
@@ -46,7 +46,7 @@ typedef struct
 {
   IdeTreeNode      *drag_node;
   IdeTreeNode      *drop_node;
-  GtkSelectionData *selection;
+  GValue            value;
   GdkDragAction     actions;
   gint              n_active;
 } DragDataReceived;
@@ -80,7 +80,7 @@ drag_data_received_free (DragDataReceived *data)
 
   g_clear_object (&data->drag_node);
   g_clear_object (&data->drop_node);
-  g_clear_pointer (&data->selection, gtk_selection_data_free);
+  g_value_unset (&data->value);
   g_slice_free (DragDataReceived, data);
 }
 
@@ -1378,19 +1378,17 @@ ide_tree_model_row_draggable (GtkTreeDragSource *source,
   return state.draggable;
 }
 
-static gboolean
+static GdkContentProvider *
 ide_tree_model_drag_data_get (GtkTreeDragSource *source,
-                              GtkTreePath       *path,
-                              GtkSelectionData  *selection)
+                              GtkTreePath       *path)
 {
   IdeTreeModel *self = (IdeTreeModel *)source;
 
   g_assert (IDE_IS_MAIN_THREAD ());
   g_assert (IDE_IS_TREE_MODEL (self));
   g_assert (path != NULL);
-  g_assert (selection != NULL);
 
-  return gtk_tree_set_row_drag_data (selection, GTK_TREE_MODEL (self), path);
+  return gtk_tree_create_row_drag_content (GTK_TREE_MODEL (self), path);
 }
 
 static gboolean
@@ -1471,7 +1469,7 @@ ide_tree_model_drag_data_received_cb (IdeExtensionSetAdapter *set,
   ide_tree_addin_node_dropped_async (addin,
                                      state->drag_node,
                                      state->drop_node,
-                                     state->selection,
+                                     &state->value,
                                      state->actions,
                                      NULL,
                                      ide_tree_model_drag_data_received_addin_cb,
@@ -1479,9 +1477,9 @@ ide_tree_model_drag_data_received_cb (IdeExtensionSetAdapter *set,
 }
 
 static gboolean
-ide_tree_model_drag_data_received (GtkTreeDragDest  *dest,
-                                   GtkTreePath      *path,
-                                   GtkSelectionData *selection)
+ide_tree_model_drag_data_received (GtkTreeDragDest *dest,
+                                   GtkTreePath     *path,
+                                   const GValue    *value)
 {
   IdeTreeModel *self = (IdeTreeModel *)dest;
   g_autoptr(GtkTreePath) source_path = NULL;
@@ -1495,9 +1493,9 @@ ide_tree_model_drag_data_received (GtkTreeDragDest  *dest,
   g_assert (IDE_IS_MAIN_THREAD ());
   g_assert (IDE_IS_TREE_MODEL (self));
   g_assert (path != NULL);
-  g_assert (selection != NULL);
+  g_assert (value != NULL);
 
-  if (gtk_tree_get_row_drag_data (selection, &source_model, &source_path))
+  if (gtk_tree_get_row_drag_data (value, &source_model, &source_path))
     {
       if (IDE_IS_TREE_MODEL (source_model))
         {
@@ -1511,10 +1509,9 @@ ide_tree_model_drag_data_received (GtkTreeDragDest  *dest,
   state = g_slice_new0 (DragDataReceived);
   g_set_object (&state->drag_node, drag_node);
   g_set_object (&state->drop_node, drop_node);
-  state->selection = gtk_selection_data_copy (selection);
+  g_value_copy (value, &state->value);
   state->actions = _ide_tree_get_drop_actions (self->tree);
 
-
   task = ide_task_new (self, NULL, NULL, NULL);
   ide_task_set_source_tag (task, ide_tree_model_drag_data_received);
   ide_task_set_task_data (task, state, drag_data_received_free);
@@ -1538,7 +1535,7 @@ ide_tree_model_row_drop_possible_cb (IdeExtensionSetAdapter *set,
   struct {
     IdeTreeNode      *drag_node;
     IdeTreeNode      *drop_node;
-    GtkSelectionData *selection;
+    const GValue     *value;
     gboolean          drop_possible;
   } *state = user_data;
 
@@ -1547,18 +1544,18 @@ ide_tree_model_row_drop_possible_cb (IdeExtensionSetAdapter *set,
   g_assert (plugin_info != NULL);
   g_assert (IDE_IS_TREE_ADDIN (exten));
   g_assert (state != NULL);
-  g_assert (state->selection != NULL);
+  g_assert (state->value != NULL);
 
   state->drop_possible |= ide_tree_addin_node_droppable (IDE_TREE_ADDIN (exten),
                                                          state->drag_node,
                                                          state->drop_node,
-                                                         state->selection);
+                                                         state->value);
 }
 
 static gboolean
-ide_tree_model_row_drop_possible (GtkTreeDragDest  *dest,
-                                  GtkTreePath      *path,
-                                  GtkSelectionData *selection)
+ide_tree_model_row_drop_possible (GtkTreeDragDest *dest,
+                                  GtkTreePath     *path,
+                                  const GValue    *value)
 {
   IdeTreeModel *self = (IdeTreeModel *)dest;
   g_autoptr(GtkTreePath) source_path = NULL;
@@ -1569,16 +1566,16 @@ ide_tree_model_row_drop_possible (GtkTreeDragDest  *dest,
   struct {
     IdeTreeNode      *drag_node;
     IdeTreeNode      *drop_node;
-    GtkSelectionData *selection;
+    const GValue     *value;
     gboolean          drop_possible;
   } state;
 
   g_assert (IDE_IS_MAIN_THREAD ());
   g_assert (IDE_IS_TREE_MODEL (self));
   g_assert (path != NULL);
-  g_assert (selection != NULL);
+  g_assert (value != NULL);
 
-  if (gtk_tree_get_row_drag_data (selection, &source_model, &source_path))
+  if (gtk_tree_get_row_drag_data (value, &source_model, &source_path))
     {
       if (IDE_IS_TREE_MODEL (source_model))
         {
@@ -1603,7 +1600,7 @@ ide_tree_model_row_drop_possible (GtkTreeDragDest  *dest,
 
   state.drag_node = drag_node;
   state.drop_node = drop_node;
-  state.selection = selection;
+  state.value = value;
   state.drop_possible = FALSE;
 
   ide_extension_set_adapter_foreach (self->addins,
diff --git a/src/libide/tree/ide-tree-node.c b/src/libide/tree/ide-tree-node.c
index 200b9ff70..680f48a03 100644
--- a/src/libide/tree/ide-tree-node.c
+++ b/src/libide/tree/ide-tree-node.c
@@ -1723,7 +1723,6 @@ ide_tree_node_show_popover_timeout_cb (gpointer data)
       break;
     }
 
-  gtk_popover_set_relative_to (popreq->popover, GTK_WIDGET (popreq->tree));
   gtk_popover_set_pointing_to (popreq->popover, &rect);
   gtk_popover_popup (popreq->popover);
 
diff --git a/src/libide/tree/ide-tree.c b/src/libide/tree/ide-tree.c
index 2c6dce4ec..837e252fc 100644
--- a/src/libide/tree/ide-tree.c
+++ b/src/libide/tree/ide-tree.c
@@ -32,6 +32,13 @@
 #include "ide-tree-node.h"
 #include "ide-tree-private.h"
 
+/* FIXME-GTK4:
+ *
+ * We still need DnD work here but that has changed so much
+ * that it would help to have a plugin using this to ensure
+ * we're porting it correctly.
+ */
+
 typedef struct
 {
   /* This #GCancellable will be automatically cancelled when the widget is
@@ -392,9 +399,8 @@ ide_tree_row_collapsed (GtkTreeView *tree_view,
 static void
 ide_tree_popup (IdeTree        *self,
                 IdeTreeNode    *node,
-                GdkEventButton *event,
-                gint            target_x,
-                gint            target_y)
+                double          target_x,
+                double          target_y)
 {
   IdeTreePrivate *priv = ide_tree_get_instance_private (self);
   const GdkRectangle area = { target_x, target_y, 0, 0 };
@@ -408,89 +414,57 @@ ide_tree_popup (IdeTree        *self,
   ide_tree_show_popover_at_node (self, node, priv->popover);
 }
 
-static gboolean
-ide_tree_button_press_event (GtkWidget      *widget,
-                             GdkEventButton *event)
+static void
+ide_tree_click_pressed_cb (IdeTree         *self,
+                           int              n_presses,
+                           double           x,
+                           double           y,
+                           GtkGestureClick *gesture)
 {
-  IdeTree *self = (IdeTree *)widget;
+  g_autoptr(GtkTreePath) path = NULL;
   IdeTreeModel *model;
+  int cell_y;
 
   g_assert (IDE_IS_TREE (self));
-  g_assert (event != NULL);
-
-  if ((model = ide_tree_get_model (self)) &&
-      (event->type == GDK_BUTTON_PRESS) &&
-      (event->button == GDK_BUTTON_SECONDARY))
-    {
-      g_autoptr(GtkTreePath) path = NULL;
-      gint cell_y;
+  g_assert (GTK_IS_GESTURE_CLICK (gesture));
 
-      if (!gtk_widget_has_focus (GTK_WIDGET (self)))
-        gtk_widget_grab_focus (GTK_WIDGET (self));
+  if (!(model = ide_tree_get_model (self)))
+    return;
 
-      gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (self),
-                                     event->x,
-                                     event->y,
-                                     &path,
-                                     NULL,
-                                     NULL,
-                                     &cell_y);
 
-      if (path == NULL)
-        {
-          ide_tree_unselect (self);
-        }
-      else
-        {
-          GtkAllocation alloc;
-          GtkTreeIter iter;
+  if (!gtk_widget_has_focus (GTK_WIDGET (self)))
+    gtk_widget_grab_focus (GTK_WIDGET (self));
 
-          gtk_widget_get_allocation (GTK_WIDGET (self), &alloc);
-
-          if (gtk_tree_model_get_iter (GTK_TREE_MODEL (model), &iter, path))
-            {
-              IdeTreeNode *node;
+  gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (self),
+                                 x,
+                                 y,
+                                 &path,
+                                 NULL,
+                                 NULL,
+                                 &cell_y);
 
-              node = ide_tree_model_get_node (IDE_TREE_MODEL (model), &iter);
-              ide_tree_select (self, node);
-              ide_tree_popup (self, node, event, alloc.x + alloc.width, event->y - cell_y);
-            }
-        }
-
-      return GDK_EVENT_STOP;
+  if (path == NULL)
+    {
+      ide_tree_unselect (self);
     }
+  else
+    {
+      GtkAllocation alloc;
+      GtkTreeIter iter;
 
-  return GTK_WIDGET_CLASS (ide_tree_parent_class)->button_press_event (widget, event);
-}
-
-static gboolean
-ide_tree_drag_motion (GtkWidget      *widget,
-                      GdkDragContext *context,
-                      gint            x,
-                      gint            y,
-                      guint           time_)
-{
-  IdeTree *self = (IdeTree *)widget;
-  IdeTreePrivate *priv = ide_tree_get_instance_private (self);
-  gboolean ret;
-
-  g_assert (IDE_IS_MAIN_THREAD ());
-  g_assert (IDE_IS_TREE (self));
-  g_assert (context != NULL);
-
-  ret = GTK_WIDGET_CLASS (ide_tree_parent_class)->drag_motion (widget, context, x, y, time_);
+      gtk_widget_get_allocation (GTK_WIDGET (self), &alloc);
 
-  /*
-   * Cache the current drop position so we can use it
-   * later to determine how to drop on a given node.
-   */
-  g_clear_pointer (&priv->drop_path, gtk_tree_path_free);
-  gtk_tree_view_get_drag_dest_row (GTK_TREE_VIEW (self), &priv->drop_path, &priv->drop_pos);
+      if (gtk_tree_model_get_iter (GTK_TREE_MODEL (model), &iter, path))
+        {
+          IdeTreeNode *node;
 
-  /* Save the drag action for builders dispatch */
-  priv->drop_action = gdk_drag_context_get_selected_action (context);
+          node = ide_tree_model_get_node (IDE_TREE_MODEL (model), &iter);
+          ide_tree_select (self, node);
+          ide_tree_popup (self, node, alloc.x + alloc.width, y - cell_y);
+        }
+    }
 
-  return ret;
+  gtk_gesture_set_state (GTK_GESTURE (gesture),  GTK_EVENT_SEQUENCE_CLAIMED);
 }
 
 static gboolean
@@ -530,6 +504,21 @@ ide_tree_query_tooltip (GtkWidget  *widget,
   return FALSE;
 }
 
+static void
+ide_tree_size_allocate (GtkWidget *widget,
+                        int        width,
+                        int        height,
+                        int        baseline)
+{
+  IdeTree *self = (IdeTree *)widget;
+  IdeTreePrivate *priv = ide_tree_get_instance_private (self);
+
+  g_assert (IDE_IS_TREE (self));
+
+  if (priv->popover != NULL)
+    gtk_popover_present (priv->popover);
+}
+
 static gboolean
 ide_tree_popup_menu_cb (IdeTree *tree,
                         gpointer user_data)
@@ -550,9 +539,9 @@ ide_tree_popup_menu_cb (IdeTree *tree,
 }
 
 static void
-ide_tree_destroy (GtkWidget *widget)
+ide_tree_dispose (GObject *object)
 {
-  IdeTree *self = (IdeTree *)widget;
+  IdeTree *self = (IdeTree *)object;
   IdeTreePrivate *priv = ide_tree_get_instance_private (self);
   IdeTreeModel *model;
 
@@ -561,8 +550,7 @@ ide_tree_destroy (GtkWidget *widget)
   if ((model = ide_tree_get_model (self)))
     _ide_tree_model_release_addins (model);
 
-  if (priv->popover != NULL)
-    gtk_widget_destroy (GTK_WIDGET (priv->popover));
+  g_clear_pointer ((GtkWidget **)&priv->popover, gtk_widget_unparent);
 
   gtk_tree_view_set_model (GTK_TREE_VIEW (self), NULL);
 
@@ -575,19 +563,20 @@ ide_tree_destroy (GtkWidget *widget)
   g_clear_pointer (&priv->header_attributes, pango_attr_list_unref);
   g_clear_pointer (&priv->drop_path, gtk_tree_path_free);
 
-  GTK_WIDGET_CLASS (ide_tree_parent_class)->destroy (widget);
+  G_OBJECT_CLASS (ide_tree_parent_class)->dispose (object);
 }
 
 static void
 ide_tree_class_init (IdeTreeClass *klass)
 {
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
   GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
   GtkTreeViewClass *tree_view_class = GTK_TREE_VIEW_CLASS (klass);
 
-  widget_class->destroy = ide_tree_destroy;
-  widget_class->button_press_event = ide_tree_button_press_event;
-  widget_class->drag_motion = ide_tree_drag_motion;
+  object_class->dispose = ide_tree_dispose;
+
   widget_class->query_tooltip = ide_tree_query_tooltip;
+  widget_class->size_allocate = ide_tree_size_allocate;
 
   tree_view_class->row_activated = ide_tree_row_activated;
   tree_view_class->row_expanded = ide_tree_row_expanded;
@@ -598,9 +587,20 @@ static void
 ide_tree_init (IdeTree *self)
 {
   IdeTreePrivate *priv = ide_tree_get_instance_private (self);
+  GtkGesture *gesture;
   GtkCellRenderer *cell;
   GtkTreeViewColumn *column;
 
+  /* Show popover on right-click */
+  gesture = gtk_gesture_click_new ();
+  gtk_gesture_single_set_button (GTK_GESTURE_SINGLE (gesture), 2);
+  g_signal_connect_object (gesture,
+                           "pressed",
+                           G_CALLBACK (ide_tree_click_pressed_cb),
+                           self,
+                           G_CONNECT_SWAPPED);
+  gtk_widget_add_controller (GTK_WIDGET (self), GTK_EVENT_CONTROLLER (gesture));
+
   priv->cancellable = g_cancellable_new ();
 
   gtk_widget_set_has_tooltip (GTK_WIDGET (self), TRUE);
@@ -654,6 +654,22 @@ ide_tree_new (void)
   return g_object_new (IDE_TYPE_TREE, NULL);
 }
 
+static void
+ide_tree_popover_closed_cb (IdeTree    *self,
+                            GtkPopover *popover)
+{
+  IdeTreePrivate *priv = ide_tree_get_instance_private (self);
+
+  g_assert (IDE_IS_TREE (self));
+  g_assert (GTK_IS_POPOVER (popover));
+
+  if (priv->popover == popover)
+    {
+      gtk_widget_unparent (GTK_WIDGET (popover));
+      priv->popover = NULL;
+    }
+}
+
 void
 ide_tree_set_context_menu (IdeTree *self,
                            GMenu   *menu)
@@ -668,16 +684,17 @@ ide_tree_set_context_menu (IdeTree *self,
       GtkTextDirection dir;
 
       if (priv->popover != NULL)
-        gtk_widget_destroy (GTK_WIDGET (priv->popover));
+        gtk_widget_unparent (GTK_WIDGET (priv->popover));
 
-      priv->popover = GTK_POPOVER (gtk_popover_new_from_model (GTK_WIDGET (self),
-                                                               G_MENU_MODEL (priv->context_menu)));
+      priv->popover = GTK_POPOVER (gtk_popover_menu_new_from_model (G_MENU_MODEL (priv->context_menu)));
       dir = gtk_widget_get_direction (GTK_WIDGET (self));
       gtk_popover_set_position (priv->popover, dir == GTK_TEXT_DIR_LTR ? GTK_POS_RIGHT : GTK_POS_LEFT);
-      g_signal_connect (priv->popover,
-                        "destroy",
-                        G_CALLBACK (gtk_widget_destroyed),
-                        &priv->popover);
+      g_signal_connect_object (priv->popover,
+                               "closed",
+                               G_CALLBACK (ide_tree_popover_closed_cb),
+                               self,
+                               G_CONNECT_SWAPPED);
+      gtk_widget_set_parent (GTK_WIDGET (priv->popover), GTK_WIDGET (self));
     }
 }
 
diff --git a/src/libide/tree/ide-tree.h b/src/libide/tree/ide-tree.h
index 0b4c16b6e..17e3fc33c 100644
--- a/src/libide/tree/ide-tree.h
+++ b/src/libide/tree/ide-tree.h
@@ -29,7 +29,7 @@ G_BEGIN_DECLS
 
 #define IDE_TYPE_TREE (ide_tree_get_type())
 
-IDE_AVAILABLE_IN_3_32
+IDE_AVAILABLE_IN_ALL
 G_DECLARE_DERIVABLE_TYPE (IdeTree, ide_tree, IDE, TREE, GtkTreeView)
 
 struct _IdeTreeClass
@@ -37,31 +37,33 @@ struct _IdeTreeClass
   GtkTreeViewClass parent_type;
 
   /*< private >*/
-  gpointer _reserved[16];
+  gpointer _reserved[8];
 };
 
-IDE_AVAILABLE_IN_3_32
-GtkWidget   *ide_tree_new                  (void);
-IDE_AVAILABLE_IN_3_32
-void         ide_tree_set_context_menu     (IdeTree     *self,
-                                            GMenu       *menu);
-IDE_AVAILABLE_IN_3_32
-void         ide_tree_show_popover_at_node (IdeTree     *self,
-                                            IdeTreeNode *node,
-                                            GtkPopover  *popover);
-IDE_AVAILABLE_IN_3_32
-IdeTreeNode *ide_tree_get_selected_node    (IdeTree     *self);
-IDE_AVAILABLE_IN_3_32
-void         ide_tree_select_node          (IdeTree     *self,
-                                            IdeTreeNode *node);
-IDE_AVAILABLE_IN_3_32
-void         ide_tree_expand_node          (IdeTree     *self,
-                                            IdeTreeNode *node);
-IDE_AVAILABLE_IN_3_32
-void         ide_tree_collapse_node        (IdeTree     *self,
-                                            IdeTreeNode *node);
-IDE_AVAILABLE_IN_3_32
-gboolean     ide_tree_node_expanded        (IdeTree     *self,
-                                            IdeTreeNode *node);
+IDE_AVAILABLE_IN_ALL
+GtkWidget     *ide_tree_new                  (void);
+IDE_AVAILABLE_IN_ALL
+void           ide_tree_set_context_menu     (IdeTree     *self,
+                                              GMenu       *menu);
+IDE_AVAILABLE_IN_ALL
+void           ide_tree_show_popover_at_node (IdeTree     *self,
+                                              IdeTreeNode *node,
+                                              GtkPopover  *popover);
+IDE_AVAILABLE_IN_ALL
+IdeTreeNode   *ide_tree_get_selected_node    (IdeTree     *self);
+IDE_AVAILABLE_IN_ALL
+void           ide_tree_select_node          (IdeTree     *self,
+                                              IdeTreeNode *node);
+IDE_AVAILABLE_IN_ALL
+void           ide_tree_expand_node          (IdeTree     *self,
+                                              IdeTreeNode *node);
+IDE_AVAILABLE_IN_ALL
+void           ide_tree_collapse_node        (IdeTree     *self,
+                                              IdeTreeNode *node);
+IDE_AVAILABLE_IN_ALL
+gboolean       ide_tree_node_expanded        (IdeTree     *self,
+                                              IdeTreeNode *node);
+IDE_AVAILABLE_IN_ALL
+GtkDropTarget *ide_tree_get_drop_target      (IdeTree     *self);
 
 G_END_DECLS


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