entry completion: Use a popover

This lets us remove a use of GTK_WINDOW_POPUP,
which should eventually be going away.

We need to disable treeview search, since it
creates a toplevel that will disrupt our grabbing
popup, causing it to be dismissed.

We don't need to grab ourselves, since the popover
code does it for us. We don't need to reposition our
window, since the popover takes care of that too.
This commit is contained in:
Matthias Clasen 2019-04-20 04:32:29 +00:00
parent 0d25233e39
commit c3c33ac168

View File

@ -79,8 +79,7 @@
#include "gtkscrolledwindow.h"
#include "gtksizerequest.h"
#include "gtkbox.h"
#include "gtkwindow.h"
#include "gtkwindowgroup.h"
#include "gtkpopover.h"
#include "gtkentry.h"
#include "gtkmain.h"
#include "gtkmarshalers.h"
@ -526,6 +525,7 @@ gtk_entry_completion_constructed (GObject *object)
G_CALLBACK (gtk_entry_completion_list_activated),
completion);
gtk_tree_view_set_enable_search (GTK_TREE_VIEW (priv->tree_view), FALSE);
gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (priv->tree_view), FALSE);
gtk_tree_view_set_hover_selection (GTK_TREE_VIEW (priv->tree_view), TRUE);
gtk_tree_view_set_activate_on_single_click (GTK_TREE_VIEW (priv->tree_view), TRUE);
@ -561,6 +561,7 @@ gtk_entry_completion_constructed (GObject *object)
g_signal_connect (priv->action_view, "row-activated",
G_CALLBACK (gtk_entry_completion_action_activated),
completion);
gtk_tree_view_set_enable_search (GTK_TREE_VIEW (priv->action_view), FALSE);
gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (priv->action_view), FALSE);
gtk_tree_view_set_hover_selection (GTK_TREE_VIEW (priv->action_view), TRUE);
gtk_tree_view_set_activate_on_single_click (GTK_TREE_VIEW (priv->action_view), TRUE);
@ -578,9 +579,8 @@ gtk_entry_completion_constructed (GObject *object)
NULL);
/* pack it all */
priv->popup_window = gtk_window_new (GTK_WINDOW_POPUP);
gtk_window_set_resizable (GTK_WINDOW (priv->popup_window), FALSE);
gtk_window_set_type_hint (GTK_WINDOW(priv->popup_window), GDK_SURFACE_TYPE_HINT_COMBO);
priv->popup_window = gtk_popover_new (NULL);
gtk_popover_set_position (GTK_POPOVER (priv->popup_window), GTK_POS_BOTTOM);
controller = gtk_event_controller_key_new ();
g_signal_connect (controller, "key-pressed",
@ -762,38 +762,12 @@ gtk_entry_completion_dispose (GObject *object)
GtkEntryCompletion *completion = GTK_ENTRY_COMPLETION (object);
GtkEntryCompletionPrivate *priv = completion->priv;
if (priv->tree_view)
{
gtk_widget_destroy (priv->tree_view);
priv->tree_view = NULL;
}
if (priv->entry)
gtk_entry_set_completion (GTK_ENTRY (priv->entry), NULL);
if (priv->actions)
{
g_object_unref (priv->actions);
priv->actions = NULL;
}
if (priv->action_view)
{
g_object_unref (priv->action_view);
priv->action_view = NULL;
}
if (priv->popup_window)
{
gtk_widget_destroy (priv->popup_window);
priv->popup_window = NULL;
}
if (priv->cell_area)
{
g_object_unref (priv->cell_area);
priv->cell_area = NULL;
}
g_clear_object (&priv->actions);
g_clear_object (&priv->action_view);
g_clear_object (&priv->cell_area);
G_OBJECT_CLASS (gtk_entry_completion_parent_class)->dispose (object);
}
@ -1461,39 +1435,11 @@ _gtk_entry_completion_resize_popup (GtkEntryCompletion *completion)
NULL, FALSE, 0.0, 0.0);
gtk_tree_path_free (path);
}
if (gtk_window_get_transient_for (GTK_WINDOW (completion->priv->popup_window)))
{
gdk_surface_move_to_rect (_gtk_widget_get_surface (completion->priv->popup_window),
&allocation,
GDK_GRAVITY_SOUTH,
GDK_GRAVITY_NORTH,
GDK_ANCHOR_FLIP_Y | GDK_ANCHOR_SLIDE_X,
0, 0);
gtk_widget_show (completion->priv->popup_window);
}
}
static void
prepare_popup_func (GdkSeat *seat,
GdkSurface *surface,
gpointer user_data)
{
GtkEntryCompletion *completion = user_data;
/* prevent the first row being focused */
gtk_widget_grab_focus (completion->priv->tree_view);
gtk_tree_selection_unselect_all (gtk_tree_view_get_selection (GTK_TREE_VIEW (completion->priv->tree_view)));
gtk_tree_selection_unselect_all (gtk_tree_view_get_selection (GTK_TREE_VIEW (completion->priv->action_view)));
gtk_widget_show (completion->priv->popup_window);
}
static void
gtk_entry_completion_popup (GtkEntryCompletion *completion)
{
GtkWidget *toplevel;
GtkText *text = gtk_entry_get_text_widget (GTK_ENTRY (completion->priv->entry));
if (gtk_widget_get_mapped (completion->priv->popup_window))
@ -1505,40 +1451,14 @@ gtk_entry_completion_popup (GtkEntryCompletion *completion)
if (!gtk_widget_has_focus (GTK_WIDGET (text)))
return;
if (completion->priv->has_grab)
return;
gtk_widget_show (completion->priv->vbox);
/* default on no match */
completion->priv->current_selected = -1;
toplevel = gtk_widget_get_toplevel (completion->priv->entry);
if (GTK_IS_WINDOW (toplevel))
{
gtk_window_set_transient_for (GTK_WINDOW (completion->priv->popup_window),
GTK_WINDOW (toplevel));
gtk_window_group_add_window (gtk_window_get_group (GTK_WINDOW (toplevel)),
GTK_WINDOW (completion->priv->popup_window));
}
gtk_window_set_display (GTK_WINDOW (completion->priv->popup_window),
gtk_widget_get_display (completion->priv->entry));
gtk_widget_realize (completion->priv->popup_window);
_gtk_entry_completion_resize_popup (completion);
if (completion->priv->device)
{
gtk_grab_add (completion->priv->popup_window);
gdk_seat_grab (gdk_device_get_seat (completion->priv->device),
gtk_widget_get_surface (completion->priv->popup_window),
GDK_SEAT_CAPABILITY_POINTER | GDK_SEAT_CAPABILITY_TOUCH,
TRUE, NULL, NULL,
prepare_popup_func, completion);
completion->priv->has_grab = TRUE;
}
gtk_popover_popup (GTK_POPOVER (completion->priv->popup_window));
}
void
@ -1547,14 +1467,7 @@ _gtk_entry_completion_popdown (GtkEntryCompletion *completion)
if (!gtk_widget_get_mapped (completion->priv->popup_window))
return;
if (completion->priv->has_grab)
{
gdk_seat_ungrab (gdk_device_get_seat (completion->priv->device));
gtk_grab_remove (completion->priv->popup_window);
completion->priv->has_grab = FALSE;
}
gtk_widget_hide (completion->priv->popup_window);
gtk_popover_popdown (GTK_POPOVER (completion->priv->popup_window));
}
static gboolean
@ -2036,8 +1949,7 @@ gtk_entry_completion_timeout (gpointer data)
}
else if (gtk_widget_get_visible (completion->priv->popup_window))
_gtk_entry_completion_popdown (completion);
return FALSE;
return G_SOURCE_REMOVE;
}
static inline gboolean
@ -2428,6 +2340,15 @@ accept_completion_callback (GtkEntryCompletion *completion)
return FALSE;
}
static gboolean
text_focus_out (GtkEntryCompletion *completion)
{
if (gtk_widget_get_mapped (completion->priv->popup_window))
return FALSE;
return accept_completion_callback (completion);
}
static void
completion_insert_text_callback (GtkText *entry,
const gchar *text,
@ -2461,7 +2382,7 @@ connect_completion_signals (GtkEntryCompletion *completion)
controller = priv->entry_key_controller = gtk_event_controller_key_new ();
g_signal_connect (controller, "key-pressed",
G_CALLBACK (gtk_entry_completion_key_pressed), completion);
g_signal_connect_swapped (controller, "focus-out", G_CALLBACK (accept_completion_callback), completion);
g_signal_connect_swapped (controller, "focus-out", G_CALLBACK (text_focus_out), completion);
gtk_widget_add_controller (GTK_WIDGET (text), controller);
completion->priv->changed_id =
@ -2548,10 +2469,8 @@ _gtk_entry_completion_disconnect (GtkEntryCompletion *completion)
unset_accessible_relation (completion->priv->popup_window,
completion->priv->entry);
gtk_window_set_attached_to (GTK_WINDOW (completion->priv->popup_window),
NULL);
gtk_window_set_transient_for (GTK_WINDOW (completion->priv->popup_window), NULL);
gtk_popover_set_relative_to (GTK_POPOVER (completion->priv->popup_window),
NULL);
completion->priv->entry = NULL;
}
@ -2564,7 +2483,7 @@ _gtk_entry_completion_connect (GtkEntryCompletion *completion,
set_accessible_relation (completion->priv->popup_window,
completion->priv->entry);
gtk_window_set_attached_to (GTK_WINDOW (completion->priv->popup_window),
gtk_popover_set_relative_to (GTK_POPOVER (completion->priv->popup_window),
completion->priv->entry);
connect_completion_signals (completion);