[gtk/dnd-gestures-2: 2/3] Update all callers



commit ec255f9bb11acdeea2ee44530f8987cddd44b610
Author: Matthias Clasen <mclasen redhat com>
Date:   Fri Jan 10 21:56:26 2020 -0500

    Update all callers

 gtk/gtkcalendar.c          |  27 +--
 gtk/gtkexpander.c          |  10 +-
 gtk/gtkfilechooserwidget.c |   6 +-
 gtk/gtkiconview.c          |  16 +-
 gtk/gtknotebook.c          |  15 +-
 gtk/gtkplacessidebar.c     |  13 +-
 gtk/gtksearchlistmodel.c   | 544 +++++++++++++++++++++++++++++++++++++++++++++
 gtk/gtksearchlistmodel.h   |  50 +++++
 gtk/gtkstackswitcher.c     |  20 +-
 gtk/gtktext.c              |  42 +++-
 gtk/gtktextview.c          |   2 +-
 gtk/gtktreeview.c          |  13 +-
 tests/testdnd.c            |   4 +-
 tests/testdnd2.c           |   2 -
 tests/testdnd3.c           |   4 +-
 15 files changed, 683 insertions(+), 85 deletions(-)
---
diff --git a/gtk/gtkcalendar.c b/gtk/gtkcalendar.c
index 8d9d36fa88..377616d143 100644
--- a/gtk/gtkcalendar.c
+++ b/gtk/gtkcalendar.c
@@ -331,10 +331,8 @@ static gboolean gtk_calendar_query_tooltip  (GtkWidget        *widget,
                                              gboolean          keyboard_mode,
                                              GtkTooltip       *tooltip);
 
-static gboolean gtk_calendar_drag_motion        (GtkDropTarget    *dest,
+static gboolean gtk_calendar_drag_accept        (GtkDropTarget    *dest,
                                                  GdkDrop          *drop,
-                                                 int               x,
-                                                 int               y,
                                                  GtkCalendar      *calendar);
 static void     gtk_calendar_drag_leave         (GtkDropTarget    *dest,
                                                  GdkDrop          *drop,
@@ -792,7 +790,7 @@ gtk_calendar_init (GtkCalendar *calendar)
   dest = gtk_drop_target_new (formats, GDK_ACTION_COPY);
   gdk_content_formats_unref (formats);
 
-  g_signal_connect (dest, "accept", G_CALLBACK (gtk_calendar_drag_motion), calendar);
+  g_signal_connect (dest, "accept", G_CALLBACK (gtk_calendar_drag_accept), calendar);
   g_signal_connect (dest, "drag-leave", G_CALLBACK (gtk_calendar_drag_leave), calendar);
   g_signal_connect (dest, "drag-drop", G_CALLBACK (gtk_calendar_drag_drop), calendar);
 
@@ -2984,7 +2982,8 @@ got_text (GObject      *source,
           GAsyncResult *result,
           gpointer      data)
 {
-  GtkCalendar *calendar = GTK_CALENDAR (data);
+  GtkDropTarget *dest = GTK_DROP_TARGET (data);
+  GtkCalendar *calendar = GTK_CALENDAR (gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (dest)));
   GtkCalendarPrivate *priv = gtk_calendar_get_instance_private (calendar);
   GdkDrop *drop = GDK_DROP (source);
   guint day, month, year;
@@ -3010,8 +3009,9 @@ got_text (GObject      *source,
         }
       else
         suggested_action = 0;
-
       gdk_drop_status (drop, suggested_action);
+      if (suggested_action == 0)
+        gtk_drop_target_deny_drop (dest, drop);
       return;
     }
 
@@ -3027,6 +3027,7 @@ got_text (GObject      *source,
       g_warning ("Received invalid date data");
       g_date_free (date);
       gdk_drop_finish (drop, 0);
+      gtk_drop_target_deny_drop (dest, drop);
       return;
     }
 
@@ -3046,23 +3047,23 @@ got_text (GObject      *source,
 }
 
 static gboolean
-gtk_calendar_drag_motion (GtkDropTarget *dest,
+gtk_calendar_drag_accept (GtkDropTarget *dest,
                           GdkDrop       *drop,
-                          int            x,
-                          int            y,
                           GtkCalendar   *calendar)
 {
   GdkAtom target;
 
   target = gtk_drop_target_find_mimetype (dest);
   if (!target || gdk_drop_get_actions (drop) == 0)
-    gdk_drop_status (drop, 0);
+    {
+      gdk_drop_status (drop, 0);
+      return FALSE;
+    }
   else if (get_status_pending (drop) == 0)
     {
       set_status_pending (drop, gdk_drop_get_actions (drop));
-      gdk_drop_read_text_async (drop, NULL, got_text, calendar);
+      gdk_drop_read_text_async (drop, NULL, got_text, dest);
     }
-
   return TRUE;
 }
 
@@ -3079,7 +3080,7 @@ gtk_calendar_drag_drop (GtkDropTarget  *dest,
   if (target != NULL)
     {
       set_status_pending (drop, 0);
-      gdk_drop_read_text_async (drop, NULL, got_text, calendar);
+      gdk_drop_read_text_async (drop, NULL, got_text, dest);
       return TRUE;
     }
 
diff --git a/gtk/gtkexpander.c b/gtk/gtkexpander.c
index 68d0a19652..f1a38acc48 100644
--- a/gtk/gtkexpander.c
+++ b/gtk/gtkexpander.c
@@ -192,10 +192,8 @@ static void     gtk_expander_size_allocate  (GtkWidget        *widget,
                                              int               baseline);
 static gboolean gtk_expander_focus          (GtkWidget        *widget,
                                              GtkDirectionType  direction);
-static gboolean gtk_expander_drag_motion    (GtkDropTarget    *dest,
+static gboolean gtk_expander_drag_accept    (GtkDropTarget    *dest,
                                              GdkDrop          *drop,
-                                             int               x,
-                                             int               y,
                                              GtkExpander      *expander);
 static void     gtk_expander_drag_leave     (GtkDropTarget    *dest,
                                              GdkDrop          *drop,
@@ -379,7 +377,7 @@ gtk_expander_init (GtkExpander *expander)
   formats = gdk_content_formats_new (NULL, 0);
   dest = gtk_drop_target_new (formats, 0);
   gdk_content_formats_unref (formats);
-  g_signal_connect (dest, "accept", G_CALLBACK (gtk_expander_drag_motion), expander);
+  g_signal_connect (dest, "accept", G_CALLBACK (gtk_expander_drag_accept), expander);
   g_signal_connect (dest, "drag-leave", G_CALLBACK (gtk_expander_drag_leave), expander);
   gtk_widget_add_controller (GTK_WIDGET (expander), GTK_EVENT_CONTROLLER (dest));
 
@@ -549,10 +547,8 @@ expand_timeout (gpointer data)
 }
 
 static gboolean
-gtk_expander_drag_motion (GtkDropTarget *dest,
+gtk_expander_drag_accept (GtkDropTarget *dest,
                           GdkDrop       *drop,
-                          int            x,
-                          int            y,
                           GtkExpander   *expander)
 {
   GtkExpanderPrivate *priv = gtk_expander_get_instance_private (expander);
diff --git a/gtk/gtkfilechooserwidget.c b/gtk/gtkfilechooserwidget.c
index 38fc967dfb..4aecc911c7 100644
--- a/gtk/gtkfilechooserwidget.c
+++ b/gtk/gtkfilechooserwidget.c
@@ -2046,10 +2046,8 @@ file_list_drag_drop_cb (GtkDropTarget        *dest,
 /* Disable the normal tree drag motion handler, it makes it look like you're
    dropping the dragged item onto a tree item */
 static gboolean
-file_list_drag_motion_cb (GtkDropTarget        *dest,
+file_list_drag_accept_cb (GtkDropTarget        *dest,
                           GdkDrop              *drop,
-                          int                   x,
-                          int                   y,
                           GtkFileChooserWidget *impl)
 {
   g_signal_stop_emission_by_name (dest, "accept");
@@ -8497,7 +8495,7 @@ post_process_ui (GtkFileChooserWidget *impl)
                                           GDK_ACTION_COPY | GDK_ACTION_MOVE);
   
   dest = gtk_drop_target_new (formats, GDK_ACTION_COPY | GDK_ACTION_MOVE);
-  g_signal_connect (dest, "accept", G_CALLBACK (file_list_drag_motion_cb), impl);
+  g_signal_connect (dest, "accept", G_CALLBACK (file_list_drag_accept_cb), impl);
   g_signal_connect (dest, "drag-drop", G_CALLBACK (file_list_drag_drop_cb), impl);
   gtk_widget_add_controller (priv->browse_files_tree_view, GTK_EVENT_CONTROLLER (dest));
   gdk_content_formats_unref (formats);
diff --git a/gtk/gtkiconview.c b/gtk/gtkiconview.c
index 94e30bee6e..c662156488 100644
--- a/gtk/gtkiconview.c
+++ b/gtk/gtkiconview.c
@@ -292,7 +292,7 @@ static GBytes * gtk_icon_view_drag_data_get     (const char      *mime_type,
 static void     gtk_icon_view_drag_leave         (GtkDropTarget    *dest,
                                                   GdkDrop          *drop,
                                                   GtkIconView      *icon_view);
-static gboolean gtk_icon_view_drag_motion        (GtkDropTarget    *dest,
+static void     gtk_icon_view_drag_motion        (GtkDropTarget    *dest,
                                                   GdkDrop          *drop,
                                                   int               x,
                                                   int               y,
@@ -6179,7 +6179,7 @@ gtk_icon_view_drag_leave (GtkDropTarget *dest,
   remove_scroll_timeout (icon_view);
 }
 
-static gboolean 
+static void
 gtk_icon_view_drag_motion (GtkDropTarget *dest,
                            GdkDrop       *drop,
                           int            x,
@@ -6193,10 +6193,10 @@ gtk_icon_view_drag_motion (GtkDropTarget *dest,
   gboolean empty;
 
   if (!set_destination (icon_view, dest, x, y, &suggested_action, &target))
-    return FALSE;
-
-  icon_view->priv->event_last_x = x;
-  icon_view->priv->event_last_y = y;
+    {
+      gdk_drop_status (drop, 0);
+      return;
+    }
 
   gtk_icon_view_get_drag_dest_item (icon_view, &path, &pos);
 
@@ -6233,8 +6233,6 @@ gtk_icon_view_drag_motion (GtkDropTarget *dest,
 
   if (path)
     gtk_tree_path_free (path);
-
-  return TRUE;
 }
 
 static gboolean 
@@ -6457,7 +6455,7 @@ gtk_icon_view_enable_model_drag_dest (GtkIconView       *icon_view,
 
   icon_view->priv->dest = gtk_drop_target_new (formats, actions);
   g_signal_connect (icon_view->priv->dest, "drag-leave", G_CALLBACK (gtk_icon_view_drag_leave), icon_view);
-  g_signal_connect (icon_view->priv->dest, "accept", G_CALLBACK (gtk_icon_view_drag_motion), icon_view);
+  g_signal_connect (icon_view->priv->dest, "drag-motion", G_CALLBACK (gtk_icon_view_drag_motion), icon_view);
   g_signal_connect (icon_view->priv->dest, "drag-drop", G_CALLBACK (gtk_icon_view_drag_drop), icon_view);
   gtk_widget_add_controller (GTK_WIDGET (icon_view), GTK_EVENT_CONTROLLER (icon_view->priv->dest));
 
diff --git a/gtk/gtknotebook.c b/gtk/gtknotebook.c
index a160ccb4eb..c8fa3c94fd 100644
--- a/gtk/gtknotebook.c
+++ b/gtk/gtknotebook.c
@@ -703,7 +703,7 @@ static void gtk_notebook_dnd_finished_cb     (GdkDrag          *drag,
 static void gtk_notebook_drag_cancel_cb      (GdkDrag          *drag,
                                               GdkDragCancelReason reason,
                                               GtkWidget        *widget);
-static gboolean gtk_notebook_drag_motion     (GtkDropTarget    *dest,
+static void     gtk_notebook_drag_motion     (GtkDropTarget    *dest,
                                               GdkDrop          *drop,
                                               int               x,
                                               int               y);
@@ -1349,7 +1349,7 @@ gtk_notebook_init (GtkNotebook *notebook)
 
   targets = gdk_content_formats_new (dst_notebook_targets, G_N_ELEMENTS (dst_notebook_targets));
   dest = gtk_drop_target_new (targets, GDK_ACTION_MOVE);
-  g_signal_connect (dest, "accept", G_CALLBACK (gtk_notebook_drag_motion), NULL);
+  g_signal_connect (dest, "drag-motion", G_CALLBACK (gtk_notebook_drag_motion), NULL);
   g_signal_connect (dest, "drag-leave", G_CALLBACK (gtk_notebook_drag_leave), NULL);
   g_signal_connect (dest, "drag-drop", G_CALLBACK (gtk_notebook_drag_drop), NULL);
   gtk_widget_add_controller (GTK_WIDGET (priv->tabs_widget), GTK_EVENT_CONTROLLER (dest));
@@ -3188,7 +3188,7 @@ gtk_notebook_switch_tab_timeout (gpointer data)
   return FALSE;
 }
 
-static gboolean
+static void
 gtk_notebook_drag_motion (GtkDropTarget *dest,
                           GdkDrop       *drop,
                           int            x,
@@ -3202,7 +3202,6 @@ gtk_notebook_drag_motion (GtkDropTarget *dest,
   GtkNotebookArrow arrow;
   GdkAtom target, tab_target;
   GList *tab;
-  gboolean retval = FALSE;
 
   arrow = gtk_notebook_get_arrow (notebook, x, y);
   if (arrow != ARROW_NONE)
@@ -3211,7 +3210,6 @@ gtk_notebook_drag_motion (GtkDropTarget *dest,
       gtk_notebook_set_scroll_timer (notebook);
       gdk_drop_status (drop, 0);
 
-      retval = TRUE;
       goto out;
     }
 
@@ -3225,8 +3223,6 @@ gtk_notebook_drag_motion (GtkDropTarget *dest,
       GtkWidget *source_child;
       GdkDrag *drag = gdk_drop_get_drag (drop);
 
-      retval = TRUE;
-
       if (!drag)
         {
           gdk_drop_status (drop, 0);
@@ -3264,8 +3260,6 @@ gtk_notebook_drag_motion (GtkDropTarget *dest,
       priv->mouse_x = x;
       priv->mouse_y = y;
 
-      retval = TRUE;
-
       if (tab != priv->switch_tab)
         remove_switch_tab_timer (notebook);
 
@@ -3282,8 +3276,7 @@ gtk_notebook_drag_motion (GtkDropTarget *dest,
       remove_switch_tab_timer (notebook);
     }
 
- out:
-  return retval;
+ out:;
 }
 
 static void
diff --git a/gtk/gtkplacessidebar.c b/gtk/gtkplacessidebar.c
index aad2385b60..82c6ddad83 100644
--- a/gtk/gtkplacessidebar.c
+++ b/gtk/gtkplacessidebar.c
@@ -1723,12 +1723,12 @@ create_placeholder_row (GtkPlacesSidebar *sidebar)
   return g_object_new (GTK_TYPE_SIDEBAR_ROW, "placeholder", TRUE, NULL);
 }
 
-static gboolean
+static void
 drag_motion_callback (GtkDropTarget *dest,
                       GdkDrop       *drop,
-                      gint       x,
-                      gint       y,
-                      gpointer   user_data)
+                      gint           x,
+                      gint           y,
+                      gpointer       user_data)
 {
   GtkPlacesSidebar *sidebar = GTK_PLACES_SIDEBAR (user_data);
   gint action;
@@ -1850,10 +1850,7 @@ drag_motion_callback (GtkDropTarget *dest,
 
  out:
   start_drop_feedback (sidebar, GTK_SIDEBAR_ROW (row), drag);
-
   gdk_drop_status (drop, action);
-
-  return TRUE;
 }
 
 /* Takes an array of URIs and turns it into a list of GFile */
@@ -4088,7 +4085,7 @@ gtk_places_sidebar_init (GtkPlacesSidebar *sidebar)
   formats = gdk_content_formats_builder_free_to_formats (builder);
   dest = gtk_drop_target_new (formats, GDK_ACTION_MOVE | GDK_ACTION_COPY | GDK_ACTION_LINK);
   gdk_content_formats_unref (formats);
-  g_signal_connect (dest, "accept", G_CALLBACK (drag_motion_callback), sidebar);
+  g_signal_connect (dest, "drag-motion", G_CALLBACK (drag_motion_callback), sidebar);
   g_signal_connect (dest, "drag-drop", G_CALLBACK (drag_drop_callback), sidebar);
   g_signal_connect (dest, "drag-leave", G_CALLBACK (drag_leave_callback), sidebar);
   gtk_widget_add_controller (sidebar->list_box, GTK_EVENT_CONTROLLER (dest));
diff --git a/gtk/gtksearchlistmodel.c b/gtk/gtksearchlistmodel.c
new file mode 100644
index 0000000000..7a50c28833
--- /dev/null
+++ b/gtk/gtksearchlistmodel.c
@@ -0,0 +1,544 @@
+/*
+ * Copyright © 2019 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors: Matthias Clasen <mclasen redhat com>
+ */
+
+#include "config.h"
+
+#include "gtksearchlistmodel.h"
+
+#include "gtkintl.h"
+#include "gtkselectionmodel.h"
+
+/**
+ * SECTION:gtksearchlistmodel
+ * @Short_description: A selection model that allows incremental searching
+ * @Title: GtkSearchListModel
+ * @see_also: #GtkSelectionModel
+ *
+ * GtkSearchListModel is an implementation of the #GtkSelectionModel interface 
+ * that allows selecting a single element. The selected element can be determined
+ * interactively via a filter.
+ */
+struct _GtkSearchListModel
+{
+  GObject parent_instance;
+
+  GListModel *model;
+  guint selected;
+  gpointer selected_item;
+
+  GtkFilter *filter;
+};
+
+struct _GtkSearchListModelClass
+{
+  GObjectClass parent_class;
+};
+
+enum {
+  PROP_0,
+  PROP_MODEL,
+  PROP_FILTER,
+  PROP_SELECTED,
+  PROP_SELECTED_ITEM,
+
+  N_PROPS
+};
+
+static GParamSpec *properties[N_PROPS] = { NULL, };
+
+static GType
+gtk_search_list_model_get_item_type (GListModel *list)
+{
+  GtkSearchListModel *self = GTK_SEARCH_LIST_MODEL (list);
+
+  return g_list_model_get_item_type (self->model);
+}
+
+static guint
+gtk_search_list_model_get_n_items (GListModel *list)
+{
+  GtkSearchListModel *self = GTK_SEARCH_LIST_MODEL (list);
+
+  return g_list_model_get_n_items (self->model);
+}
+
+static gpointer
+gtk_search_list_model_get_item (GListModel *list,
+                                guint       position)
+{
+  GtkSearchListModel *self = GTK_SEARCH_LIST_MODEL (list);
+
+  return g_list_model_get_item (self->model, position);
+}
+
+static void
+gtk_search_list_model_list_model_init (GListModelInterface *iface)
+{
+  iface->get_item_type = gtk_search_list_model_get_item_type;
+  iface->get_n_items = gtk_search_list_model_get_n_items;
+  iface->get_item = gtk_search_list_model_get_item;
+}
+
+static gboolean
+gtk_search_list_model_is_selected (GtkSelectionModel *model,
+                                   guint              position)
+{
+  GtkSearchListModel *self = GTK_SEARCH_LIST_MODEL (model);
+
+  return self->selected == position;
+}
+
+static void
+gtk_search_list_model_query_range (GtkSelectionModel *model,
+                                   guint              position,
+                                   guint             *start_range,
+                                   guint             *n_range,
+                                   gboolean          *selected)
+{
+  GtkSearchListModel *self = GTK_SEARCH_LIST_MODEL (model);
+  guint n_items;
+
+  n_items = g_list_model_get_n_items (self->model);
+
+  if (position >= n_items)
+    {
+      *start_range = position;
+      *n_range = 0;
+      *selected = FALSE;
+    }
+  else if (self->selected == GTK_INVALID_LIST_POSITION)
+    {
+      *start_range = 0;
+      *n_range = n_items;
+      *selected = FALSE;
+    }
+  else if (position < self->selected)
+    {
+      *start_range = 0;
+      *n_range = self->selected;
+      *selected = FALSE;
+    }
+  else if (position > self->selected)
+    {
+      *start_range = self->selected + 1;
+      *n_range = n_items - *start_range;
+      *selected = FALSE;
+    }
+  else
+    {
+      *start_range = self->selected;
+      *n_range = 1;
+      *selected = TRUE;
+    }
+}
+
+static void
+gtk_search_list_model_selection_model_init (GtkSelectionModelInterface *iface)
+{
+  iface->is_selected = gtk_search_list_model_is_selected; 
+  iface->query_range = gtk_search_list_model_query_range;
+}
+
+G_DEFINE_TYPE_EXTENDED (GtkSearchListModel, gtk_search_list_model, G_TYPE_OBJECT, 0,
+                        G_IMPLEMENT_INTERFACE (G_TYPE_LIST_MODEL,
+                                               gtk_search_list_model_list_model_init)
+                        G_IMPLEMENT_INTERFACE (GTK_TYPE_SELECTION_MODEL,
+                                               gtk_search_list_model_selection_model_init))
+
+static void
+gtk_search_list_model_items_changed_cb (GListModel         *model,
+                                        guint               position,
+                                        guint               removed,
+                                        guint               added,
+                                        GtkSearchListModel *self)
+{
+  g_object_freeze_notify (G_OBJECT (self));
+
+  if (self->selected_item == NULL)
+    {
+      /* nothing to do */
+    }
+  else if (self->selected < position)
+    {
+      /* unchanged */
+    }
+  else if (self->selected >= position + removed)
+    {
+      self->selected += added - removed;
+      g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_SELECTED]);
+      g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_SELECTED_ITEM]);
+    }
+  else
+    {
+      guint i;
+
+      for (i = 0; i < added; i++)
+        {
+          gpointer item = g_list_model_get_item (model, position + i);
+          if (item == self->selected_item)
+            {
+              /* the item moved */
+              //TODO refilter
+              if (self->selected != position + i)
+                {
+                  self->selected = position + i;
+                  g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_SELECTED]);
+                  g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_SELECTED_ITEM]);
+                }
+              break;
+            }
+        }
+      if (i == added)
+        {
+          /* the item really was deleted */
+          g_clear_object (&self->selected_item);
+          self->selected = GTK_INVALID_LIST_POSITION;
+          //TODO refilter
+          g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_SELECTED]);
+          g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_SELECTED_ITEM]);
+        }
+    }
+
+  g_list_model_items_changed (G_LIST_MODEL (self), position, removed, added);
+
+  g_object_thaw_notify (G_OBJECT (self));
+}
+
+static void
+set_selected (GtkSearchListModel *self,
+              guint               position)
+{
+  gpointer new_selected = NULL;
+  guint old_position;
+
+  if (self->selected == position)
+    return;
+
+  new_selected = g_list_model_get_item (self->model, position);
+
+  if (new_selected == NULL)
+    position = GTK_INVALID_LIST_POSITION;
+
+  if (self->selected == position)
+    return;
+
+  old_position = self->selected;
+  self->selected = position;
+  g_clear_object (&self->selected_item);
+  self->selected_item = new_selected;
+
+  if (old_position == GTK_INVALID_LIST_POSITION)
+    gtk_selection_model_selection_changed (GTK_SELECTION_MODEL (self), position, 1);
+  else if (position == GTK_INVALID_LIST_POSITION)
+    gtk_selection_model_selection_changed (GTK_SELECTION_MODEL (self), old_position, 1);
+  else if (position < old_position)
+    gtk_selection_model_selection_changed (GTK_SELECTION_MODEL (self), position, old_position - position + 
1);
+  else
+    gtk_selection_model_selection_changed (GTK_SELECTION_MODEL (self), old_position, position - old_position 
+ 1);
+
+  g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_SELECTED]);
+  g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_SELECTED_ITEM]);
+}
+
+static gboolean
+match_item (GtkSearchListModel *self,
+            guint               position)
+{
+  gpointer item;
+  gboolean result;
+
+  item = g_list_model_get_item (self->model, position);
+  result = gtk_filter_match (self->filter, item);
+  g_object_unref (item);
+
+  return result;
+}
+
+static guint
+find_next_match (GtkSearchListModel *self,
+                 guint               position,
+                 gboolean            forward)
+{
+  guint i;
+
+  if (position == GTK_INVALID_LIST_POSITION)
+    position = 0;
+
+  g_print ("search %s from %u\n", forward ? "forward" : "backward", position); 
+  if (forward)
+    for (i = position; i < g_list_model_get_n_items (self->model); i++)
+      {
+        if (match_item (self, i))
+          return i;
+      }
+  else
+    for (i = position; ; i--)
+      {
+        if (match_item (self, i))
+          return i;
+        if (i == 0)
+          break;
+      }
+
+  return GTK_INVALID_LIST_POSITION;
+}
+
+static void
+gtk_search_list_model_filter_changed_cb (GtkFilter          *filter,
+                                         GtkFilterChange     change,
+                                         GtkSearchListModel *self)
+{
+  guint position;
+
+g_print ("filter changed: change %d, strictness %d\n", change, gtk_filter_get_strictness (self->filter));
+
+  if (gtk_filter_get_strictness (self->filter) == GTK_FILTER_MATCH_NONE)
+    position = GTK_INVALID_LIST_POSITION;
+  else
+    switch (change)
+      {
+      case GTK_FILTER_CHANGE_DIFFERENT:
+      case GTK_FILTER_CHANGE_LESS_STRICT:
+        position = find_next_match (self, 0, TRUE);
+        break;
+      case GTK_FILTER_CHANGE_MORE_STRICT:
+        position = find_next_match (self, self->selected, TRUE);
+        break;
+      default:
+        g_assert_not_reached ();
+      }
+
+  g_print ("select %u\n", position);
+  set_selected (self, position);
+}
+
+static void
+gtk_search_list_model_clear_model (GtkSearchListModel *self)
+{
+  if (self->model == NULL)
+    return;
+
+  g_signal_handlers_disconnect_by_func (self->model, 
+                                        gtk_search_list_model_items_changed_cb,
+                                        self);
+  g_clear_object (&self->model);
+}
+
+static void
+gtk_search_list_model_clear_filter (GtkSearchListModel *self)
+{
+  if (self->filter == NULL)
+    return;
+
+  g_signal_handlers_disconnect_by_func (self->filter, 
+                                        gtk_search_list_model_filter_changed_cb,
+                                        self);
+
+  g_clear_object (&self->filter);
+}
+
+static void
+gtk_search_list_model_set_property (GObject      *object,
+                                    guint         prop_id,
+                                    const GValue *value,
+                                    GParamSpec   *pspec)
+
+{
+  GtkSearchListModel *self = GTK_SEARCH_LIST_MODEL (object);
+
+  switch (prop_id)
+    {
+    case PROP_MODEL:
+      self->model = g_value_dup_object (value);
+      g_signal_connect (self->model, "items-changed",
+                        G_CALLBACK (gtk_search_list_model_items_changed_cb), self);
+      break;
+
+    case PROP_FILTER:
+      self->filter = g_value_dup_object (value);
+      g_signal_connect (self->filter, "changed",
+                        G_CALLBACK (gtk_search_list_model_filter_changed_cb), self);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    }
+}
+
+static void
+gtk_search_list_model_get_property (GObject    *object,
+                                    guint       prop_id,
+                                    GValue     *value,
+                                    GParamSpec *pspec)
+{
+  GtkSearchListModel *self = GTK_SEARCH_LIST_MODEL (object);
+
+  switch (prop_id)
+    {
+    case PROP_MODEL:
+      g_value_set_object (value, self->model);
+      break;
+
+    case PROP_FILTER:
+      g_value_set_object (value, self->filter);
+      break;
+
+    case PROP_SELECTED:
+      g_value_set_uint (value, self->selected);
+      break;
+
+    case PROP_SELECTED_ITEM:
+      g_value_set_object (value, self->selected_item);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    }
+}
+
+static void
+gtk_search_list_model_dispose (GObject *object)
+{
+  GtkSearchListModel *self = GTK_SEARCH_LIST_MODEL (object);
+
+  gtk_search_list_model_clear_model (self);
+  gtk_search_list_model_clear_filter (self);
+
+  self->selected = GTK_INVALID_LIST_POSITION;
+  g_clear_object (&self->selected_item);
+
+  G_OBJECT_CLASS (gtk_search_list_model_parent_class)->dispose (object);
+}
+
+static void
+gtk_search_list_model_class_init (GtkSearchListModelClass *klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+  gobject_class->get_property = gtk_search_list_model_get_property;
+  gobject_class->set_property = gtk_search_list_model_set_property;
+  gobject_class->dispose = gtk_search_list_model_dispose;
+
+  /**
+   * GtkSearchListModel:selected:
+   *
+   * Position of the selected item
+   */
+  properties[PROP_SELECTED] =
+    g_param_spec_uint ("selected",
+                       P_("Selected"),
+                       P_("Position of the selected item"),
+                       0, G_MAXUINT, GTK_INVALID_LIST_POSITION,
+                       G_PARAM_READABLE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
+
+  /**
+   * GtkSearchListModel:selected-item:
+   *
+   * The selected item
+   */
+  properties[PROP_SELECTED_ITEM] =
+    g_param_spec_object ("selected-item",
+                       P_("Selected Item"),
+                       P_("The selected item"),
+                       G_TYPE_OBJECT,
+                       G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
+
+  /**
+   * GtkSearchListModel:model:
+   *
+   * The model being managed
+   */
+  properties[PROP_MODEL] =
+    g_param_spec_object ("model",
+                         P_("The model"),
+                         P_("The model being managed"),
+                         G_TYPE_LIST_MODEL,
+                         G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
+
+  /**
+   * GtkSearchListModel:filter:
+   *
+   * The filter determining the selected item
+   */
+  properties[PROP_FILTER] =
+    g_param_spec_object ("filter",
+                         P_("The filter"),
+                         P_("The filter being used"),
+                         GTK_TYPE_FILTER,
+                         G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
+
+  g_object_class_install_properties (gobject_class, N_PROPS, properties);
+}
+
+static void
+gtk_search_list_model_init (GtkSearchListModel *self)
+{
+  self->selected = GTK_INVALID_LIST_POSITION;
+}
+
+/**
+ * gtk_search_list_model_new:
+ * @model: (transfer none): the #GListModel to manage
+ * @filter: (transfer none): the #GtkFilter to use
+ *
+ * Creates a new selection to handle @model.
+ *
+ * Returns: (transfer full) (type GtkSearchListModel): a new #GtkSearchListModel
+ **/
+GtkSearchListModel *
+gtk_search_list_model_new (GListModel *model,
+                           GtkFilter  *filter)
+{
+  g_return_val_if_fail (G_IS_LIST_MODEL (model), NULL);
+
+  return g_object_new (GTK_TYPE_SEARCH_LIST_MODEL,
+                       "model", model,
+                       "filter", filter,
+                       NULL);
+}
+
+gboolean
+gtk_search_list_model_next_match (GtkSearchListModel *self)
+{
+  guint position;
+
+  position = find_next_match (self, self->selected, TRUE);
+  if (position == GTK_INVALID_LIST_POSITION)
+    return FALSE;
+
+  set_selected (self, position);
+
+  return TRUE;
+}
+
+gboolean
+gtk_search_list_model_previous_match (GtkSearchListModel *self)
+{
+  guint position;
+
+  position = find_next_match (self, self->selected, FALSE);
+  if (position == GTK_INVALID_LIST_POSITION)
+    return FALSE;
+
+  set_selected (self, position);
+
+  return TRUE;
+}
diff --git a/gtk/gtksearchlistmodel.h b/gtk/gtksearchlistmodel.h
new file mode 100644
index 0000000000..324449bbcd
--- /dev/null
+++ b/gtk/gtksearchlistmodel.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright © 2019 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors: Matthias Clasen <mclasen redhat com>
+ */
+
+#ifndef __GTK_SEARCH_LIST_MODEL_H__
+#define __GTK_SEARCH_LIST_MODEL_H__
+
+
+#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION)
+#error "Only <gtk/gtk.h> can be included directly."
+#endif
+
+#include <gio/gio.h>
+#include <gtk/gtkfilter.h>
+
+
+G_BEGIN_DECLS
+
+#define GTK_TYPE_SEARCH_LIST_MODEL (gtk_search_list_model_get_type ())
+
+GDK_AVAILABLE_IN_ALL
+G_DECLARE_FINAL_TYPE (GtkSearchListModel, gtk_search_list_model, GTK, SEARCH_LIST_MODEL, GObject)
+
+GDK_AVAILABLE_IN_ALL
+GtkSearchListModel *    gtk_search_list_model_new               (GListModel             *model,
+                                                                 GtkFilter              *filter);
+GDK_AVAILABLE_IN_ALL
+gboolean                gtk_search_list_model_next_match        (GtkSearchListModel     *self);
+
+GDK_AVAILABLE_IN_ALL
+gboolean                gtk_search_list_model_previous_match    (GtkSearchListModel     *self);
+
+G_END_DECLS
+
+#endif /* __GTK_SEARCH_LIST_MODEL_H__ */
diff --git a/gtk/gtkstackswitcher.c b/gtk/gtkstackswitcher.c
index a5f3bbaeb1..c9d30fecf1 100644
--- a/gtk/gtkstackswitcher.c
+++ b/gtk/gtkstackswitcher.c
@@ -95,7 +95,10 @@ enum {
 static void     gtk_stack_switcher_drag_leave  (GtkDropTarget    *dest,
                                                 GdkDrop          *drop,
                                                 GtkStackSwitcher *self);
-static gboolean gtk_stack_switcher_drag_motion (GtkDropTarget    *dest,
+static gboolean gtk_stack_switcher_drag_accept (GtkDropTarget    *dest,
+                                                GdkDrop          *drop,
+                                                GtkStackSwitcher *self);
+static void     gtk_stack_switcher_drag_motion (GtkDropTarget    *dest,
                                                 GdkDrop          *drop,
                                                 int               x,
                                                 int               y,
@@ -121,7 +124,8 @@ gtk_stack_switcher_init (GtkStackSwitcher *switcher)
   dest = gtk_drop_target_new (formats, 0);
   gdk_content_formats_unref (formats);
   g_signal_connect (dest, "drag-leave", G_CALLBACK (gtk_stack_switcher_drag_leave), switcher);
-  g_signal_connect (dest, "accept", G_CALLBACK (gtk_stack_switcher_drag_motion), switcher);
+  g_signal_connect (dest, "accept", G_CALLBACK (gtk_stack_switcher_drag_accept), switcher);
+  g_signal_connect (dest, "drag-motion", G_CALLBACK (gtk_stack_switcher_drag_motion), switcher);
   gtk_widget_add_controller (GTK_WIDGET (switcher), GTK_EVENT_CONTROLLER (dest));
 }
 
@@ -264,6 +268,14 @@ gtk_stack_switcher_switch_timeout (gpointer data)
 }
 
 static gboolean
+gtk_stack_switcher_drag_accept (GtkDropTarget    *dest,
+                                GdkDrop          *drop,
+                                GtkStackSwitcher *self)
+{
+  return TRUE;
+}
+
+static void 
 gtk_stack_switcher_drag_motion (GtkDropTarget    *dest,
                                 GdkDrop          *drop,
                                 int               x,
@@ -274,7 +286,6 @@ gtk_stack_switcher_drag_motion (GtkDropTarget    *dest,
   GtkWidget *button;
   GHashTableIter iter;
   gpointer value;
-  gboolean retval = FALSE;
 
   button = NULL;
   g_hash_table_iter_init (&iter, priv->buttons);
@@ -285,7 +296,6 @@ gtk_stack_switcher_drag_motion (GtkDropTarget    *dest,
       if (gtk_widget_contains (GTK_WIDGET (value), cx, cy))
         {
           button = GTK_WIDGET (value);
-          retval = TRUE;
           break;
         }
     }
@@ -302,8 +312,6 @@ gtk_stack_switcher_drag_motion (GtkDropTarget    *dest,
                                           self);
       g_source_set_name_by_id (priv->switch_timer, "[gtk] gtk_stack_switcher_switch_timeout");
     }
-
-  return retval;
 }
 
 static void
diff --git a/gtk/gtktext.c b/gtk/gtktext.c
index 0c775301ec..45b9b3c82c 100644
--- a/gtk/gtktext.c
+++ b/gtk/gtktext.c
@@ -339,7 +339,10 @@ static gboolean gtk_text_drag_drop          (GtkDropTarget    *dest,
                                              int               x,
                                              int               y,
                                              GtkText          *text);
-static gboolean gtk_text_drag_motion        (GtkDropTarget    *dest,
+static gboolean gtk_text_drag_accept        (GtkDropTarget    *dest,
+                                             GdkDrop          *drop,
+                                             GtkText          *self);
+static void     gtk_text_drag_motion        (GtkDropTarget    *dest,
                                              GdkDrop          *drop,
                                              int               x,
                                              int               y,
@@ -1732,7 +1735,8 @@ gtk_text_init (GtkText *self)
 
   formats = gdk_content_formats_new_for_gtype (G_TYPE_STRING);
   dest = gtk_drop_target_new (formats, GDK_ACTION_COPY | GDK_ACTION_MOVE);
-  g_signal_connect (dest, "accept", G_CALLBACK (gtk_text_drag_motion), self);
+  g_signal_connect (dest, "accept", G_CALLBACK (gtk_text_drag_accept), self);
+  g_signal_connect (dest, "drag-motion", G_CALLBACK (gtk_text_drag_motion), self);
   g_signal_connect (dest, "drag-leave", G_CALLBACK (gtk_text_drag_leave), self);
   g_signal_connect (dest, "drag-drop", G_CALLBACK (gtk_text_drag_drop), self);
   gdk_content_formats_unref (formats);
@@ -6230,6 +6234,29 @@ gtk_text_drag_drop (GtkDropTarget *dest,
 }
 
 static gboolean
+gtk_text_drag_accept (GtkDropTarget *dest,
+                      GdkDrop       *drop,
+                      GtkText       *self)
+{
+  GtkTextPrivate *priv = gtk_text_get_instance_private (self);
+  GdkDragAction suggested_action;
+
+  if (priv->editable &&
+      gtk_drop_target_find_mimetype (dest) != NULL)
+    {
+      suggested_action = GDK_ACTION_COPY | GDK_ACTION_MOVE;
+    }
+  else
+    {
+      /* Entry not editable, or no text */
+      suggested_action = 0;
+    }
+
+  gdk_drop_status (drop, suggested_action);
+  return suggested_action != 0;
+}
+
+static void
 gtk_text_drag_motion (GtkDropTarget *dest,
                       GdkDrop       *drop,
                       int            x,
@@ -6237,8 +6264,6 @@ gtk_text_drag_motion (GtkDropTarget *dest,
                       GtkText        *self)
 {
   GtkTextPrivate *priv = gtk_text_get_instance_private (self);
-  GtkWidget *widget = GTK_WIDGET (self);
-  GdkDragAction suggested_action;
   int new_position, old_position;
 
   old_position = priv->dnd_position;
@@ -6247,8 +6272,6 @@ gtk_text_drag_motion (GtkDropTarget *dest,
   if (priv->editable &&
       gtk_drop_target_find_mimetype (dest) != NULL)
     {
-      suggested_action = GDK_ACTION_COPY | GDK_ACTION_MOVE;
-
       if (priv->selection_bound == priv->current_pos ||
           new_position < priv->selection_bound ||
           new_position > priv->current_pos)
@@ -6263,16 +6286,11 @@ gtk_text_drag_motion (GtkDropTarget *dest,
   else
     {
       /* Entry not editable, or no text */
-      suggested_action = 0;
       priv->dnd_position = -1;
     }
 
-  gdk_drop_status (drop, suggested_action);
-
   if (priv->dnd_position != old_position)
-    gtk_widget_queue_draw (widget);
-
-  return TRUE;
+    gtk_widget_queue_draw (GTK_WIDGET (self));
 }
 
 /* We display the cursor when
diff --git a/gtk/gtktextview.c b/gtk/gtktextview.c
index 21d0635a05..ed5f6ad90d 100644
--- a/gtk/gtktextview.c
+++ b/gtk/gtktextview.c
@@ -1638,7 +1638,7 @@ gtk_text_view_init (GtkTextView *text_view)
   dest = gtk_drop_target_new (formats, GDK_ACTION_COPY | GDK_ACTION_MOVE);
   gdk_content_formats_unref (formats);
   g_signal_connect (dest, "drag-leave", G_CALLBACK (gtk_text_view_drag_leave), text_view);
-  g_signal_connect (dest, "accept", G_CALLBACK (gtk_text_view_drag_motion), text_view);
+  g_signal_connect (dest, "drag-motion", G_CALLBACK (gtk_text_view_drag_motion), text_view);
   g_signal_connect (dest, "drag-drop", G_CALLBACK (gtk_text_view_drag_drop), text_view);
   gtk_widget_add_controller (GTK_WIDGET (text_view), GTK_EVENT_CONTROLLER (dest));
 
diff --git a/gtk/gtktreeview.c b/gtk/gtktreeview.c
index 6dc7fa4004..003204cf1b 100644
--- a/gtk/gtktreeview.c
+++ b/gtk/gtktreeview.c
@@ -695,7 +695,7 @@ static GBytes *gtk_tree_view_drag_data_get (const char *mimetype,
 static void     gtk_tree_view_drag_leave         (GtkDropTarget    *dest,
                                                   GdkDrop          *drop,
                                                   GtkTreeView      *tree_view);
-static gboolean gtk_tree_view_drag_motion        (GtkDropTarget    *dest,
+static void     gtk_tree_view_drag_motion        (GtkDropTarget    *dest,
                                                   GdkDrop          *drop,
                                                   int               x,
                                                   int               y,
@@ -7244,7 +7244,7 @@ gtk_tree_view_drag_leave (GtkDropTarget *dest,
 }
 
 
-static gboolean
+static void
 gtk_tree_view_drag_motion (GtkDropTarget *dest,
                            GdkDrop       *drop,
                            int            x,
@@ -7258,7 +7258,10 @@ gtk_tree_view_drag_motion (GtkDropTarget *dest,
   GdkAtom target;
 
   if (!set_destination_row (tree_view, dest, x, y, &suggested_action, &target))
-    return FALSE;
+    {
+      gdk_drop_status (drop, 0);
+      return;
+    }
 
   tree_view->event_last_x = x;
   tree_view->event_last_y = y;
@@ -7305,8 +7308,6 @@ gtk_tree_view_drag_motion (GtkDropTarget *dest,
 
   if (path)
     gtk_tree_path_free (path);
-
-  return TRUE;
 }
 
 
@@ -12924,7 +12925,7 @@ gtk_tree_view_enable_model_drag_dest (GtkTreeView       *tree_view,
 
   di->dest = gtk_drop_target_new (formats, actions);
   g_signal_connect (di->dest, "drag-leave", G_CALLBACK (gtk_tree_view_drag_leave), tree_view);
-  g_signal_connect (di->dest, "accept", G_CALLBACK (gtk_tree_view_drag_motion), tree_view);
+  g_signal_connect (di->dest, "drag-motion", G_CALLBACK (gtk_tree_view_drag_motion), tree_view);
   g_signal_connect (di->dest, "drag-drop", G_CALLBACK (gtk_tree_view_drag_drop), tree_view);
   gtk_widget_add_controller (GTK_WIDGET (tree_view), GTK_EVENT_CONTROLLER (di->dest));
   g_object_ref (di->dest);
diff --git a/tests/testdnd.c b/tests/testdnd.c
index 42d55589bb..54df81423e 100644
--- a/tests/testdnd.c
+++ b/tests/testdnd.c
@@ -445,9 +445,7 @@ popdown_cb (gpointer data)
 
 gboolean
 popup_motion (GtkDropTarget *dest,
-              GdkDrop       *drop,
-              int            x,
-              int            y)
+              GdkDrop       *drop)
 {
   gdk_drop_status (drop, GDK_ACTION_COPY);
   return TRUE;
diff --git a/tests/testdnd2.c b/tests/testdnd2.c
index 09cefbfae9..ecf5a95551 100644
--- a/tests/testdnd2.c
+++ b/tests/testdnd2.c
@@ -179,8 +179,6 @@ delayed_deny (gpointer data)
 static gboolean
 image_drag_motion (GtkDropTarget    *dest,
                    GdkDrop          *drop,
-                   int               x,
-                   int               y,
                    gpointer          data)
 {
   GtkWidget *image = data;
diff --git a/tests/testdnd3.c b/tests/testdnd3.c
index 5f2bb0e92b..f9315569fc 100644
--- a/tests/testdnd3.c
+++ b/tests/testdnd3.c
@@ -221,9 +221,7 @@ item_drag_drop (GtkDropTarget *dest,
 
 static gboolean
 item_drag_motion (GtkDropTarget *dest,
-                  GdkDrop       *drop,
-                  int            x,
-                  int            y)
+                  GdkDrop       *drop)
 {
   if (gtk_drop_target_find_mimetype (dest) != NULL)
     {



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