[gtk+] GtkTreeView: Rework the search window hack so it also works on Wayland



commit aedd193c69f5857917369c083be04bd24a1e770e
Author: Jonas Ådahl <jadahl gmail com>
Date:   Sun Oct 18 21:23:12 2015 +0800

    GtkTreeView: Rework the search window hack so it also works on Wayland
    
    The search window of a tree view was implemented by showing without
    making it visible by by positioning it outside the screen edge. This is
    not possible on Wayland, so implement another method for being able to
    enter text into a non-visible entry.
    
    The new method is implemented by, before showing the window, pass the
    key event directly to the IM context backing the entry. If the key
    event triggered the context to commit new text or change the preedit
    content, the search window is shown, and from that point the key events
    are forwarded directly to the entry widget.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=756780

 gtk/gtktreeview.c |  137 ++++++++++++++++++++++++++++------------------------
 1 files changed, 74 insertions(+), 63 deletions(-)
---
diff --git a/gtk/gtktreeview.c b/gtk/gtktreeview.c
index 415a5e6..80c7eab 100644
--- a/gtk/gtktreeview.c
+++ b/gtk/gtktreeview.c
@@ -801,6 +801,9 @@ static void     gtk_tree_view_search_disable_popdown    (GtkEntry         *entry
                                                         gpointer          data);
 static void     gtk_tree_view_search_preedit_changed    (GtkIMContext     *im_context,
                                                         GtkTreeView      *tree_view);
+static void     gtk_tree_view_search_commit             (GtkIMContext     *im_context,
+                                                         gchar            *buf,
+                                                         GtkTreeView      *tree_view);
 static void     gtk_tree_view_search_activate           (GtkEntry         *entry,
                                                         GtkTreeView      *tree_view);
 static gboolean gtk_tree_view_real_search_enable_popdown(gpointer          data);
@@ -5987,73 +5990,73 @@ gtk_tree_view_key_press (GtkWidget   *widget,
       return FALSE;
     }
 
-  /* We pass the event to the search_entry.  If its text changes, then we start
-   * the typeahead find capabilities. */
+  /* Initially, before the search window is visible, we pass the event to the
+   * IM context of the search entry box. If it triggers a commit or a preedit,
+   * we then show the search window without loosing tree view focus.
+   * If the seach window is already visible, we forward the events to it,
+   * keeping the focus on the tree view.
+   */
   if (gtk_widget_has_focus (GTK_WIDGET (tree_view))
       && tree_view->priv->enable_search
       && !tree_view->priv->search_custom_entry_set
       && !gtk_tree_view_search_key_cancels_search (event->keyval))
     {
-      GdkEvent *new_event;
-      char *old_text;
-      const char *new_text;
-      gboolean retval;
-      GdkScreen *screen;
-      gboolean text_modified;
-      gulong popup_menu_id;
+      GtkWidget *search_window;
 
       gtk_tree_view_ensure_interactive_directory (tree_view);
 
-      /* Make a copy of the current text */
-      old_text = g_strdup (gtk_entry_get_text (GTK_ENTRY (tree_view->priv->search_entry)));
-      new_event = gdk_event_copy ((GdkEvent *) event);
-      g_object_unref (((GdkEventKey *) new_event)->window);
-      ((GdkEventKey *) new_event)->window = g_object_ref (gtk_widget_get_window 
(tree_view->priv->search_window));
-      gtk_widget_realize (tree_view->priv->search_window);
-
-      popup_menu_id = g_signal_connect (tree_view->priv->search_entry, 
-                                       "popup-menu", G_CALLBACK (gtk_true),
-                                        NULL);
-
-      /* Move the entry off screen */
-      screen = gtk_widget_get_screen (GTK_WIDGET (tree_view));
-      gtk_window_move (GTK_WINDOW (tree_view->priv->search_window),
-                      gdk_screen_get_width (screen) + 1,
-                      gdk_screen_get_height (screen) + 1);
-      gtk_widget_show (tree_view->priv->search_window);
-
-      /* Send the event to the window.  If the preedit_changed signal is emitted
-       * during this event, we will set priv->imcontext_changed  */
-      tree_view->priv->imcontext_changed = FALSE;
-      retval = gtk_widget_event (tree_view->priv->search_window, new_event);
-      gdk_event_free (new_event);
-      gtk_widget_hide (tree_view->priv->search_window);
-
-      g_signal_handler_disconnect (tree_view->priv->search_entry, 
-                                  popup_menu_id);
-
-      /* We check to make sure that the entry tried to handle the text, and that
-       * the text has changed.
-       */
-      new_text = gtk_entry_get_text (GTK_ENTRY (tree_view->priv->search_entry));
-      text_modified = strcmp (old_text, new_text) != 0;
-      g_free (old_text);
-      if (tree_view->priv->imcontext_changed ||    /* we're in a preedit */
-         (retval && text_modified))               /* ...or the text was modified */
-       {
-         if (gtk_tree_view_real_start_interactive_search (tree_view,
-                                                           gdk_event_get_device ((GdkEvent *) event),
-                                                           FALSE))
-           {
-             gtk_widget_grab_focus (GTK_WIDGET (tree_view));
-             return TRUE;
-           }
-         else
-           {
-             gtk_entry_set_text (GTK_ENTRY (tree_view->priv->search_entry), "");
-             return FALSE;
-           }
-       }
+      search_window = tree_view->priv->search_window;
+      if (!gtk_widget_is_visible (search_window))
+        {
+          GtkIMContext *im_context =
+            _gtk_entry_get_im_context (GTK_ENTRY (tree_view->priv->search_entry));
+
+          tree_view->priv->imcontext_changed = FALSE;
+          gtk_im_context_filter_keypress (im_context, event);
+
+          if (tree_view->priv->imcontext_changed)
+            {
+              GdkDevice *device;
+
+              device = gdk_event_get_device ((GdkEvent *) event);
+              if (gtk_tree_view_real_start_interactive_search (tree_view,
+                                                               device,
+                                                               FALSE))
+                {
+                  gtk_widget_grab_focus (GTK_WIDGET (tree_view));
+                  return TRUE;
+                }
+              else
+                {
+                  gtk_entry_set_text (GTK_ENTRY (tree_view->priv->search_entry), "");
+                  return FALSE;
+                }
+            }
+        }
+      else
+        {
+          GdkEvent *new_event;
+          gulong popup_menu_id;
+
+          new_event = gdk_event_copy ((GdkEvent *) event);
+          g_object_unref (((GdkEventKey *) new_event)->window);
+          ((GdkEventKey *) new_event)->window =
+            g_object_ref (gtk_widget_get_window (search_window));
+          gtk_widget_realize (search_window);
+
+          popup_menu_id = g_signal_connect (tree_view->priv->search_entry,
+                                            "popup-menu", G_CALLBACK (gtk_true),
+                                            NULL);
+
+          /* Because we keep the focus on the treeview, we need to forward the
+           * key events to the entry, when it is visible. */
+          gtk_widget_event (search_window, new_event);
+          gdk_event_free (new_event);
+
+          g_signal_handler_disconnect (tree_view->priv->search_entry,
+                                       popup_menu_id);
+
+        }
     }
 
   return FALSE;
@@ -11072,8 +11075,11 @@ gtk_tree_view_ensure_interactive_directory (GtkTreeView *tree_view)
                                 GTK_WINDOW (tree_view->priv->search_window));
 
   gtk_window_set_type_hint (GTK_WINDOW (tree_view->priv->search_window),
-                           GDK_WINDOW_TYPE_HINT_UTILITY);
+                            GDK_WINDOW_TYPE_HINT_UTILITY);
   gtk_window_set_modal (GTK_WINDOW (tree_view->priv->search_window), TRUE);
+  gtk_window_set_transient_for (GTK_WINDOW (tree_view->priv->search_window),
+                                GTK_WINDOW (toplevel));
+
   g_signal_connect (tree_view->priv->search_window, "delete-event",
                    G_CALLBACK (gtk_tree_view_search_delete_event),
                    tree_view);
@@ -11111,6 +11117,10 @@ gtk_tree_view_ensure_interactive_directory (GtkTreeView *tree_view)
                    "preedit-changed",
                    G_CALLBACK (gtk_tree_view_search_preedit_changed),
                    tree_view);
+  g_signal_connect (_gtk_entry_get_im_context (GTK_ENTRY (tree_view->priv->search_entry)),
+                   "commit",
+                   G_CALLBACK (gtk_tree_view_search_commit),
+                   tree_view);
 
   gtk_container_add (GTK_CONTAINER (vbox),
                     tree_view->priv->search_entry);
@@ -11176,6 +11186,10 @@ gtk_tree_view_real_start_interactive_search (GtkTreeView *tree_view,
 
   /* done, show it */
   tree_view->priv->search_position_func (tree_view, tree_view->priv->search_window, 
tree_view->priv->search_position_user_data);
+
+  /* Grab focus without selecting all the text. */
+  gtk_entry_grab_focus_without_selecting (GTK_ENTRY (tree_view->priv->search_entry));
+
   gtk_widget_show (tree_view->priv->search_window);
   if (tree_view->priv->search_entry_changed_id == 0)
     {
@@ -11191,9 +11205,6 @@ gtk_tree_view_real_start_interactive_search (GtkTreeView *tree_view,
                   tree_view);
   g_source_set_name_by_id (tree_view->priv->typeselect_flush_timeout, "[gtk+] 
gtk_tree_view_search_entry_flush_timeout");
 
-  /* Grab focus without selecting all the text. */
-  _gtk_entry_grab_focus (GTK_ENTRY (tree_view->priv->search_entry), FALSE);
-
   /* send focus-in event */
   send_focus_change (tree_view->priv->search_entry, device, TRUE);
 


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