[gtk/kill-tree-menu: 52/52] treeview: Use a popover for search



commit b5ada1e9b14b056dbe96f4333e2acecdd0423ec9
Author: Matthias Clasen <mclasen redhat com>
Date:   Sat Dec 28 12:57:17 2019 -0500

    treeview: Use a popover for search
    
    This is a more modern way of doing things, and
    avoids a GtkWindow of type popup. With a popover,
    it doesn't make sense to have a positioning
    function, so remove that api.

 docs/reference/gtk/gtk4-sections.txt |   3 -
 gtk/gtktreeview.c                    | 264 +++++++----------------------------
 gtk/gtktreeview.h                    |  10 --
 3 files changed, 48 insertions(+), 229 deletions(-)
---
diff --git a/docs/reference/gtk/gtk4-sections.txt b/docs/reference/gtk/gtk4-sections.txt
index d011835273..33702f6eff 100644
--- a/docs/reference/gtk/gtk4-sections.txt
+++ b/docs/reference/gtk/gtk4-sections.txt
@@ -3698,9 +3698,6 @@ gtk_tree_view_get_search_equal_func
 gtk_tree_view_set_search_equal_func
 gtk_tree_view_get_search_entry
 gtk_tree_view_set_search_entry
-GtkTreeViewSearchPositionFunc
-gtk_tree_view_get_search_position_func
-gtk_tree_view_set_search_position_func
 gtk_tree_view_get_fixed_height_mode
 gtk_tree_view_set_fixed_height_mode
 gtk_tree_view_get_hover_selection
diff --git a/gtk/gtktreeview.c b/gtk/gtktreeview.c
index d5d9272a4e..6d4709cc5d 100644
--- a/gtk/gtktreeview.c
+++ b/gtk/gtktreeview.c
@@ -63,6 +63,7 @@
 #include "gtkwidgetprivate.h"
 #include "gtkwindowgroup.h"
 #include "gtknative.h"
+#include "gtkpopover.h"
 
 #include "a11y/gtktreeviewaccessibleprivate.h"
 
@@ -474,13 +475,12 @@ struct _GtkTreeView
   /* Interactive search */
   gint selected_iter;
   gint search_column;
-  GtkTreeViewSearchPositionFunc search_position_func;
   GtkTreeViewSearchEqualFunc search_equal_func;
   gpointer search_user_data;
   GDestroyNotify search_destroy;
   gpointer search_position_user_data;
   GDestroyNotify search_position_destroy;
-  GtkWidget *search_window;
+  GtkWidget *search_popover;
   GtkWidget *search_entry;
   gulong search_entry_changed_id;
   guint typeselect_flush_timeout;
@@ -835,12 +835,9 @@ static inline gint gtk_tree_view_get_row_height              (GtkTreeView
 
 /* interactive search */
 static void     gtk_tree_view_ensure_interactive_directory (GtkTreeView *tree_view);
-static void     gtk_tree_view_search_window_hide        (GtkWidget        *search_window,
+static void     gtk_tree_view_search_popover_hide       (GtkWidget        *search_popover,
                                                          GtkTreeView      *tree_view,
                                                          GdkDevice        *device);
-static void     gtk_tree_view_search_position_func      (GtkTreeView      *tree_view,
-                                                        GtkWidget        *search_window,
-                                                        gpointer          user_data);
 static void     gtk_tree_view_search_preedit_changed    (GtkText          *text,
                                                          const char       *preedit,
                                                         GtkTreeView      *tree_view);
@@ -1757,7 +1754,6 @@ gtk_tree_view_init (GtkTreeView *tree_view)
   tree_view->selection = _gtk_tree_selection_new_with_tree_view (tree_view);
   tree_view->enable_search = TRUE;
   tree_view->search_column = -1;
-  tree_view->search_position_func = gtk_tree_view_search_position_func;
   tree_view->search_equal_func = gtk_tree_view_search_equal_func;
   tree_view->search_custom_entry_set = FALSE;
   tree_view->typeselect_flush_timeout = 0;
@@ -2097,11 +2093,11 @@ gtk_tree_view_free_rbtree (GtkTreeView *tree_view)
 }
 
 static void
-gtk_tree_view_destroy_search_window (GtkTreeView *tree_view)
+gtk_tree_view_destroy_search_popover (GtkTreeView *tree_view)
 {
-  gtk_widget_destroy (tree_view->search_window);
+  gtk_widget_destroy (tree_view->search_popover);
 
-  tree_view->search_window = NULL;
+  tree_view->search_popover = NULL;
   tree_view->search_entry = NULL;
   tree_view->search_entry_changed_id = 0;
 }
@@ -2157,9 +2153,9 @@ gtk_tree_view_destroy (GtkWidget *widget)
   tree_view->anchor = NULL;
 
   /* destroy interactive search dialog */
-  if (tree_view->search_window)
+  if (tree_view->search_popover)
     {
-      gtk_tree_view_destroy_search_window (tree_view);
+      gtk_tree_view_destroy_search_popover (tree_view);
       if (tree_view->typeselect_flush_timeout)
        {
          g_source_remove (tree_view->typeselect_flush_timeout);
@@ -2706,6 +2702,9 @@ gtk_tree_view_size_allocate (GtkWidget *widget,
       gtk_tree_path_free (path);
       gtk_widget_size_allocate (child->widget, &child_rect, -1);
     }
+
+  if (tree_view->search_popover)
+    gtk_native_check_resize (GTK_NATIVE (tree_view->search_popover));
 }
 
 /* Grabs the focus and unsets the GTK_TREE_VIEW_DRAW_KEYFOCUS flag */
@@ -5300,12 +5299,6 @@ gtk_tree_view_search_key_cancels_search (guint keyval)
       || keyval == GDK_KEY_ISO_Left_Tab;
 }
 
-static gboolean
-no_popup (void)
-{
-  return TRUE;
-}
-
 static gboolean
 gtk_tree_view_key_controller_key_pressed (GtkEventControllerKey *key,
                                           guint                  keyval,
@@ -5462,14 +5455,12 @@ gtk_tree_view_key_controller_key_pressed (GtkEventControllerKey *key,
       && !tree_view->search_custom_entry_set
       && !gtk_tree_view_search_key_cancels_search (keyval))
     {
-      GtkWidget *search_window;
-
       gtk_tree_view_ensure_interactive_directory (tree_view);
 
-      search_window = tree_view->search_window;
-      if (!gtk_widget_is_visible (search_window))
+      if (!gtk_widget_is_visible (tree_view->search_popover))
         {
           tree_view->imcontext_changed = FALSE;
+          
           gtk_event_controller_key_forward (key, tree_view->search_entry);
 
           if (tree_view->imcontext_changed)
@@ -5477,35 +5468,9 @@ gtk_tree_view_key_controller_key_pressed (GtkEventControllerKey *key,
               GdkDevice *device;
 
               device = gtk_get_current_event_device ();
-              if (gtk_tree_view_real_start_interactive_search (tree_view,
-                                                               device,
-                                                               FALSE))
-                {
-                  gtk_widget_grab_focus (GTK_WIDGET (tree_view));
-                  return TRUE;
-                }
-              else
-                {
-                  gtk_editable_set_text (GTK_EDITABLE (tree_view->search_entry), "");
-                  return FALSE;
-                }
+              return gtk_tree_view_real_start_interactive_search (tree_view, device, FALSE);
             }
         }
-      else
-        {
-          gulong popup_menu_id;
-
-          popup_menu_id = g_signal_connect (tree_view->search_entry,
-                                            "popup-menu", G_CALLBACK (no_popup),
-                                            NULL);
-
-          /* Because we keep the focus on the treeview, we need to forward the
-           * key events to the entry, when it is visible. */
-          gtk_event_controller_key_forward (key, search_window);
-
-          g_signal_handler_disconnect (tree_view->search_entry,
-                                       popup_menu_id);
-        }
     }
 
   return FALSE;
@@ -5589,11 +5554,9 @@ gtk_tree_view_key_controller_focus_out (GtkEventControllerKey *key,
                 "contains-focus", &contains_focus,
                 NULL);
 
-  /* destroy interactive search dialog */
-  if (tree_view->search_window &&
-      !gtk_event_controller_key_contains_focus (key))
-    gtk_tree_view_search_window_hide (tree_view->search_window, tree_view,
-                                      gtk_get_current_event_device ());
+  if (tree_view->search_popover && !gtk_event_controller_key_contains_focus (key))
+    gtk_tree_view_search_popover_hide (tree_view->search_popover, tree_view,
+                                       gtk_get_current_event_device ());
 }
 
 /* Incremental Reflow
@@ -10164,117 +10127,49 @@ gtk_tree_view_real_select_cursor_parent (GtkTreeView *tree_view)
 static gboolean
 gtk_tree_view_search_entry_flush_timeout (GtkTreeView *tree_view)
 {
-  gtk_tree_view_search_window_hide (tree_view->search_window, tree_view, NULL);
+  gtk_tree_view_search_popover_hide (tree_view->search_popover, tree_view, NULL);
   tree_view->typeselect_flush_timeout = 0;
 
   return FALSE;
 }
 
-/* Cut and paste from gtkwindow.c */
-static void
-send_focus_change (GtkWidget *widget,
-                   GdkDevice *device,
-                  gboolean   in)
-{
-  GdkSeat *seat;
-  GList *devices, *d;
-
-  seat = gdk_display_get_default_seat (gtk_widget_get_display (widget));
-  devices = gdk_seat_get_slaves (seat, GDK_SEAT_CAPABILITY_KEYBOARD);
-  devices = g_list_prepend (devices, gdk_seat_get_keyboard (seat));
-
-  for (d = devices; d; d = d->next)
-    {
-      GdkEvent *fevent;
-      GdkSurface *surface;
-
-      surface = gtk_native_get_surface (gtk_widget_get_native (widget));
-
-      fevent = gdk_event_new (GDK_FOCUS_CHANGE);
-
-      fevent->any.type = GDK_FOCUS_CHANGE;
-      fevent->any.surface = g_object_ref (surface);
-      fevent->focus_change.in = in;
-      gdk_event_set_device (fevent, device);
-
-      gtk_widget_set_has_focus (widget, in);
-      gtk_widget_event (widget, fevent);
-
-      g_object_unref (fevent);
-    }
-
-  g_list_free (devices);
-}
-
 static void
 gtk_tree_view_ensure_interactive_directory (GtkTreeView *tree_view)
 {
-  GtkWidget *frame, *vbox, *toplevel;
-  GdkDisplay *display;
   GtkEventController *controller;
   GtkGesture *gesture;
 
   if (tree_view->search_custom_entry_set)
     return;
 
-  toplevel = GTK_WIDGET (gtk_widget_get_root (GTK_WIDGET (tree_view)));
-  display = gtk_widget_get_display (GTK_WIDGET (tree_view));
-
-   if (tree_view->search_window != NULL)
-     {
-       if (gtk_window_has_group (GTK_WINDOW (toplevel)))
-         gtk_window_group_add_window (gtk_window_get_group (GTK_WINDOW (toplevel)),
-                                      GTK_WINDOW (tree_view->search_window));
-       else if (gtk_window_has_group (GTK_WINDOW (tree_view->search_window)))
-         gtk_window_group_remove_window (gtk_window_get_group (GTK_WINDOW (tree_view->search_window)),
-                                         GTK_WINDOW (tree_view->search_window));
-
-       gtk_window_set_display (GTK_WINDOW (tree_view->search_window), display);
-
-       return;
-     }
-   
-  tree_view->search_window = gtk_window_new (GTK_WINDOW_POPUP);
-  gtk_window_set_display (GTK_WINDOW (tree_view->search_window), display);
-
-  if (gtk_window_has_group (GTK_WINDOW (toplevel)))
-    gtk_window_group_add_window (gtk_window_get_group (GTK_WINDOW (toplevel)),
-                                GTK_WINDOW (tree_view->search_window));
+  if (tree_view->search_popover)
+    return;
 
-  gtk_window_set_type_hint (GTK_WINDOW (tree_view->search_window),
-                            GDK_SURFACE_TYPE_HINT_UTILITY);
-  gtk_window_set_modal (GTK_WINDOW (tree_view->search_window), TRUE);
-  gtk_window_set_transient_for (GTK_WINDOW (tree_view->search_window),
-                                GTK_WINDOW (toplevel));
+  tree_view->search_popover = gtk_popover_new (GTK_WIDGET (tree_view));
+  gtk_popover_set_autohide (GTK_POPOVER (tree_view->search_popover), FALSE);
 
   controller = gtk_event_controller_key_new ();
   g_signal_connect (controller, "key-pressed",
                    G_CALLBACK (gtk_tree_view_search_key_pressed),
                    tree_view);
-  gtk_widget_add_controller (tree_view->search_window, controller);
+  gtk_widget_add_controller (tree_view->search_popover, controller);
 
   gesture = gtk_gesture_click_new ();
   g_signal_connect (gesture, "pressed",
                     G_CALLBACK (gtk_tree_view_search_pressed_cb), tree_view);
-  gtk_widget_add_controller (tree_view->search_window, GTK_EVENT_CONTROLLER (gesture));
+  gtk_widget_add_controller (tree_view->search_popover, GTK_EVENT_CONTROLLER (gesture));
 
   controller = gtk_event_controller_scroll_new (GTK_EVENT_CONTROLLER_SCROLL_VERTICAL);
   g_signal_connect (controller, "scroll",
                    G_CALLBACK (gtk_tree_view_search_scroll_event),
                    tree_view);
-  gtk_widget_add_controller (tree_view->search_window, controller);
+  gtk_widget_add_controller (tree_view->search_popover, controller);
 
-  frame = gtk_frame_new (NULL);
-  gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_IN);
-  gtk_widget_show (frame);
-  gtk_container_add (GTK_CONTAINER (tree_view->search_window), frame);
+  tree_view->search_entry = gtk_text_new ();
 
-  vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
-  gtk_widget_show (vbox);
-  gtk_container_add (GTK_CONTAINER (frame), vbox);
+  controller = gtk_text_get_key_controller (GTK_TEXT (tree_view->search_entry));
+  gtk_event_controller_set_propagation_limit (controller, GTK_LIMIT_NONE);
 
-  /* add entry */
-  tree_view->search_entry = gtk_text_new ();
   g_signal_connect (tree_view->search_entry, "activate",
                     G_CALLBACK (gtk_tree_view_search_activate), tree_view);
   g_signal_connect (tree_view->search_entry, "preedit-changed",
@@ -10282,8 +10177,7 @@ gtk_tree_view_ensure_interactive_directory (GtkTreeView *tree_view)
   g_signal_connect (tree_view->search_entry, "changed",
                    G_CALLBACK (gtk_tree_view_search_changed), tree_view);
 
-  gtk_container_add (GTK_CONTAINER (vbox),
-                    tree_view->search_entry);
+  gtk_container_add (GTK_CONTAINER (tree_view->search_popover), tree_view->search_entry);
 
   gtk_widget_realize (tree_view->search_entry);
 }
@@ -10309,8 +10203,8 @@ gtk_tree_view_real_start_interactive_search (GtkTreeView *tree_view,
   if (tree_view->search_custom_entry_set)
     return FALSE;
 
-  if (tree_view->search_window != NULL &&
-      gtk_widget_get_visible (tree_view->search_window))
+  if (tree_view->search_popover &&
+      gtk_widget_get_visible (tree_view->search_popover))
     return TRUE;
 
   for (list = tree_view->columns; list; list = list->next)
@@ -10344,16 +10238,13 @@ gtk_tree_view_real_start_interactive_search (GtkTreeView *tree_view,
   if (keybinding)
     gtk_editable_set_text (GTK_EDITABLE (tree_view->search_entry), "");
 
-  /* done, show it */
-  tree_view->search_position_func (tree_view, tree_view->search_window, 
tree_view->search_position_user_data);
-
   /* Grab focus without selecting all the text. */
   if (GTK_IS_ENTRY (tree_view->search_entry))
     gtk_entry_grab_focus_without_selecting (GTK_ENTRY (tree_view->search_entry));
   else
     gtk_widget_grab_focus (tree_view->search_entry);
 
-  gtk_widget_show (tree_view->search_window);
+  gtk_popover_popup (GTK_POPOVER (tree_view->search_popover));
   if (tree_view->search_entry_changed_id == 0)
     {
       tree_view->search_entry_changed_id =
@@ -10368,9 +10259,6 @@ gtk_tree_view_real_start_interactive_search (GtkTreeView *tree_view,
                    tree_view);
   g_source_set_name_by_id (tree_view->typeselect_flush_timeout, "[gtk] 
gtk_tree_view_search_entry_flush_timeout");
 
-  /* send focus-in event */
-  send_focus_change (tree_view->search_entry, device, TRUE);
-
   /* search first matching iter */
   gtk_tree_view_search_init (tree_view->search_entry, tree_view);
 
@@ -13709,9 +13597,9 @@ gtk_tree_view_set_search_entry (GtkTreeView *tree_view,
 
       g_object_unref (tree_view->search_entry);
     }
-  else if (tree_view->search_window)
+  else if (tree_view->search_popover)
     {
-      gtk_tree_view_destroy_search_window (tree_view);
+      gtk_tree_view_destroy_search_popover (tree_view);
     }
 
   if (entry)
@@ -13745,55 +13633,10 @@ gtk_tree_view_set_search_entry (GtkTreeView *tree_view,
     }
 }
 
-/**
- * gtk_tree_view_set_search_position_func:
- * @tree_view: A #GtkTreeView
- * @func: (allow-none): the function to use to position the search dialog, or %NULL
- *    to use the default search position function
- * @data: (allow-none): user data to pass to @func, or %NULL
- * @destroy: (allow-none): Destroy notifier for @data, or %NULL
- *
- * Sets the function to use when positioning the search dialog.
- **/
-void
-gtk_tree_view_set_search_position_func (GtkTreeView                   *tree_view,
-                                       GtkTreeViewSearchPositionFunc  func,
-                                       gpointer                       user_data,
-                                       GDestroyNotify                 destroy)
-{
-  g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
-
-  if (tree_view->search_position_destroy)
-    tree_view->search_position_destroy (tree_view->search_position_user_data);
-
-  tree_view->search_position_func = func;
-  tree_view->search_position_user_data = user_data;
-  tree_view->search_position_destroy = destroy;
-  if (tree_view->search_position_func == NULL)
-    tree_view->search_position_func = gtk_tree_view_search_position_func;
-}
-
-/**
- * gtk_tree_view_get_search_position_func: (skip)
- * @tree_view: A #GtkTreeView
- *
- * Returns the positioning function currently in use.
- *
- * Returns: the currently used function for positioning the search dialog.
- */
-GtkTreeViewSearchPositionFunc
-gtk_tree_view_get_search_position_func (GtkTreeView *tree_view)
-{
-  g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
-
-  return tree_view->search_position_func;
-}
-
-
 static void
-gtk_tree_view_search_window_hide (GtkWidget   *search_window,
-                                  GtkTreeView *tree_view,
-                                  GdkDevice   *device)
+gtk_tree_view_search_popover_hide (GtkWidget   *search_popover,
+                                   GtkTreeView *tree_view,
+                                   GdkDevice   *device)
 {
   if (tree_view->disable_popdown)
     return;
@@ -13810,23 +13653,14 @@ gtk_tree_view_search_window_hide (GtkWidget   *search_window,
       tree_view->typeselect_flush_timeout = 0;
     }
        
-  if (gtk_widget_get_visible (search_window))
+  if (gtk_widget_get_visible (search_popover))
     {
-      /* send focus-in event */
-      send_focus_change (GTK_WIDGET (tree_view->search_entry), device, FALSE);
-      gtk_widget_hide (search_window);
-      gtk_editable_set_text (GTK_EDITABLE(tree_view->search_entry), "");
-      send_focus_change (GTK_WIDGET (tree_view), device, TRUE);
+      gtk_popover_popdown (GTK_POPOVER (search_popover));
+      gtk_editable_set_text (GTK_EDITABLE (tree_view->search_entry), "");
+      gtk_widget_grab_focus (GTK_WIDGET (tree_view));
     }
 }
 
-static void
-gtk_tree_view_search_position_func (GtkTreeView *tree_view,
-                                   GtkWidget   *search_window,
-                                   gpointer     user_data)
-{
-}
-
 /* Because we're visible but offscreen, we just set a flag in the preedit
  * callback.
  */
@@ -13861,9 +13695,9 @@ gtk_tree_view_search_activate (GtkEntry    *entry,
 {
   GtkTreePath *path;
 
-  gtk_tree_view_search_window_hide (tree_view->search_window,
-                                    tree_view,
-                                    gtk_get_current_event_device ());
+  gtk_tree_view_search_popover_hide (tree_view->search_popover,
+                                     tree_view,
+                                     gtk_get_current_event_device ());
 
   /* If we have a row selected and it's the cursor row, we activate
    * the row XXX */
@@ -13889,13 +13723,11 @@ gtk_tree_view_search_pressed_cb (GtkGesture  *gesture,
   GdkDevice *keyb_device;
   GdkEventSequence *sequence;
   const GdkEvent *event;
-  GtkWidget *widget;
 
   sequence = gtk_gesture_get_last_updated_sequence (gesture);
   event = gtk_gesture_get_last_event (gesture, sequence);
   keyb_device = gdk_device_get_associated_device (gdk_event_get_device (event));
-  widget = gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (gesture));
-  gtk_tree_view_search_window_hide (widget, tree_view, keyb_device);
+  gtk_tree_view_search_popover_hide (tree_view->search_popover, tree_view, keyb_device);
 }
 
 static gboolean
@@ -13946,8 +13778,8 @@ gtk_tree_view_search_key_pressed (GtkEventControllerKey *key,
   if (!tree_view->search_custom_entry_set
       && gtk_tree_view_search_key_cancels_search (keyval))
     {
-      gtk_tree_view_search_window_hide (widget, tree_view,
-                                        gtk_get_current_event_device ());
+      gtk_tree_view_search_popover_hide (tree_view->search_popover, tree_view,
+                                         gtk_get_current_event_device ());
       return TRUE;
     }
 
@@ -14012,7 +13844,7 @@ gtk_tree_view_search_key_pressed (GtkEventControllerKey *key,
  *  nothing was found, and TRUE otherwise.
  */
 static gboolean
-gtk_tree_view_search_move (GtkWidget   *window,
+gtk_tree_view_search_move (GtkWidget   *popover,
                           GtkTreeView *tree_view,
                           gboolean     up)
 {
diff --git a/gtk/gtktreeview.h b/gtk/gtktreeview.h
index 70c3e557ac..9125c14063 100644
--- a/gtk/gtktreeview.h
+++ b/gtk/gtktreeview.h
@@ -133,9 +133,6 @@ typedef gboolean (*GtkTreeViewSearchEqualFunc) (GtkTreeModel            *model,
 typedef gboolean (*GtkTreeViewRowSeparatorFunc) (GtkTreeModel      *model,
                                                 GtkTreeIter       *iter,
                                                 gpointer           data);
-typedef void     (*GtkTreeViewSearchPositionFunc) (GtkTreeView  *tree_view,
-                                                  GtkWidget    *search_dialog,
-                                                  gpointer      user_data);
 
 
 /* Creators */
@@ -374,13 +371,6 @@ GtkEditable                  *gtk_tree_view_get_search_entry         (GtkTreeVie
 GDK_AVAILABLE_IN_ALL
 void                          gtk_tree_view_set_search_entry         (GtkTreeView                   
*tree_view,
                                                                      GtkEditable                   *entry);
-GDK_AVAILABLE_IN_ALL
-GtkTreeViewSearchPositionFunc gtk_tree_view_get_search_position_func (GtkTreeView                   
*tree_view);
-GDK_AVAILABLE_IN_ALL
-void                          gtk_tree_view_set_search_position_func (GtkTreeView                   
*tree_view,
-                                                                     GtkTreeViewSearchPositionFunc  func,
-                                                                     gpointer                       data,
-                                                                     GDestroyNotify                 destroy);
 
 /* Convert between the different coordinate systems */
 GDK_AVAILABLE_IN_ALL


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