forked from AuroraMiddleware/gtk
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
This commit is contained in:
parent
bcb28adba3
commit
aedd193c69
@ -801,6 +801,9 @@ static void gtk_tree_view_search_disable_popdown (GtkEntry *entry
|
|||||||
gpointer data);
|
gpointer data);
|
||||||
static void gtk_tree_view_search_preedit_changed (GtkIMContext *im_context,
|
static void gtk_tree_view_search_preedit_changed (GtkIMContext *im_context,
|
||||||
GtkTreeView *tree_view);
|
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,
|
static void gtk_tree_view_search_activate (GtkEntry *entry,
|
||||||
GtkTreeView *tree_view);
|
GtkTreeView *tree_view);
|
||||||
static gboolean gtk_tree_view_real_search_enable_popdown(gpointer data);
|
static gboolean gtk_tree_view_real_search_enable_popdown(gpointer data);
|
||||||
@ -5987,73 +5990,73 @@ gtk_tree_view_key_press (GtkWidget *widget,
|
|||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* We pass the event to the search_entry. If its text changes, then we start
|
/* Initially, before the search window is visible, we pass the event to the
|
||||||
* the typeahead find capabilities. */
|
* 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))
|
if (gtk_widget_has_focus (GTK_WIDGET (tree_view))
|
||||||
&& tree_view->priv->enable_search
|
&& tree_view->priv->enable_search
|
||||||
&& !tree_view->priv->search_custom_entry_set
|
&& !tree_view->priv->search_custom_entry_set
|
||||||
&& !gtk_tree_view_search_key_cancels_search (event->keyval))
|
&& !gtk_tree_view_search_key_cancels_search (event->keyval))
|
||||||
{
|
{
|
||||||
GdkEvent *new_event;
|
GtkWidget *search_window;
|
||||||
char *old_text;
|
|
||||||
const char *new_text;
|
|
||||||
gboolean retval;
|
|
||||||
GdkScreen *screen;
|
|
||||||
gboolean text_modified;
|
|
||||||
gulong popup_menu_id;
|
|
||||||
|
|
||||||
gtk_tree_view_ensure_interactive_directory (tree_view);
|
gtk_tree_view_ensure_interactive_directory (tree_view);
|
||||||
|
|
||||||
/* Make a copy of the current text */
|
search_window = tree_view->priv->search_window;
|
||||||
old_text = g_strdup (gtk_entry_get_text (GTK_ENTRY (tree_view->priv->search_entry)));
|
if (!gtk_widget_is_visible (search_window))
|
||||||
new_event = gdk_event_copy ((GdkEvent *) event);
|
{
|
||||||
g_object_unref (((GdkEventKey *) new_event)->window);
|
GtkIMContext *im_context =
|
||||||
((GdkEventKey *) new_event)->window = g_object_ref (gtk_widget_get_window (tree_view->priv->search_window));
|
_gtk_entry_get_im_context (GTK_ENTRY (tree_view->priv->search_entry));
|
||||||
gtk_widget_realize (tree_view->priv->search_window);
|
|
||||||
|
|
||||||
popup_menu_id = g_signal_connect (tree_view->priv->search_entry,
|
tree_view->priv->imcontext_changed = FALSE;
|
||||||
"popup-menu", G_CALLBACK (gtk_true),
|
gtk_im_context_filter_keypress (im_context, event);
|
||||||
NULL);
|
|
||||||
|
|
||||||
/* Move the entry off screen */
|
if (tree_view->priv->imcontext_changed)
|
||||||
screen = gtk_widget_get_screen (GTK_WIDGET (tree_view));
|
{
|
||||||
gtk_window_move (GTK_WINDOW (tree_view->priv->search_window),
|
GdkDevice *device;
|
||||||
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
|
device = gdk_event_get_device ((GdkEvent *) event);
|
||||||
* during this event, we will set priv->imcontext_changed */
|
if (gtk_tree_view_real_start_interactive_search (tree_view,
|
||||||
tree_view->priv->imcontext_changed = FALSE;
|
device,
|
||||||
retval = gtk_widget_event (tree_view->priv->search_window, new_event);
|
FALSE))
|
||||||
gdk_event_free (new_event);
|
{
|
||||||
gtk_widget_hide (tree_view->priv->search_window);
|
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;
|
||||||
|
|
||||||
g_signal_handler_disconnect (tree_view->priv->search_entry,
|
new_event = gdk_event_copy ((GdkEvent *) event);
|
||||||
popup_menu_id);
|
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);
|
||||||
|
|
||||||
/* We check to make sure that the entry tried to handle the text, and that
|
popup_menu_id = g_signal_connect (tree_view->priv->search_entry,
|
||||||
* the text has changed.
|
"popup-menu", G_CALLBACK (gtk_true),
|
||||||
*/
|
NULL);
|
||||||
new_text = gtk_entry_get_text (GTK_ENTRY (tree_view->priv->search_entry));
|
|
||||||
text_modified = strcmp (old_text, new_text) != 0;
|
/* Because we keep the focus on the treeview, we need to forward the
|
||||||
g_free (old_text);
|
* key events to the entry, when it is visible. */
|
||||||
if (tree_view->priv->imcontext_changed || /* we're in a preedit */
|
gtk_widget_event (search_window, new_event);
|
||||||
(retval && text_modified)) /* ...or the text was modified */
|
gdk_event_free (new_event);
|
||||||
{
|
|
||||||
if (gtk_tree_view_real_start_interactive_search (tree_view,
|
g_signal_handler_disconnect (tree_view->priv->search_entry,
|
||||||
gdk_event_get_device ((GdkEvent *) event),
|
popup_menu_id);
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return FALSE;
|
return FALSE;
|
||||||
@ -11072,8 +11075,11 @@ gtk_tree_view_ensure_interactive_directory (GtkTreeView *tree_view)
|
|||||||
GTK_WINDOW (tree_view->priv->search_window));
|
GTK_WINDOW (tree_view->priv->search_window));
|
||||||
|
|
||||||
gtk_window_set_type_hint (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_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_signal_connect (tree_view->priv->search_window, "delete-event",
|
||||||
G_CALLBACK (gtk_tree_view_search_delete_event),
|
G_CALLBACK (gtk_tree_view_search_delete_event),
|
||||||
tree_view);
|
tree_view);
|
||||||
@ -11111,6 +11117,10 @@ gtk_tree_view_ensure_interactive_directory (GtkTreeView *tree_view)
|
|||||||
"preedit-changed",
|
"preedit-changed",
|
||||||
G_CALLBACK (gtk_tree_view_search_preedit_changed),
|
G_CALLBACK (gtk_tree_view_search_preedit_changed),
|
||||||
tree_view);
|
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),
|
gtk_container_add (GTK_CONTAINER (vbox),
|
||||||
tree_view->priv->search_entry);
|
tree_view->priv->search_entry);
|
||||||
@ -11176,6 +11186,10 @@ gtk_tree_view_real_start_interactive_search (GtkTreeView *tree_view,
|
|||||||
|
|
||||||
/* done, show it */
|
/* done, show it */
|
||||||
tree_view->priv->search_position_func (tree_view, tree_view->priv->search_window, tree_view->priv->search_position_user_data);
|
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);
|
gtk_widget_show (tree_view->priv->search_window);
|
||||||
if (tree_view->priv->search_entry_changed_id == 0)
|
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);
|
tree_view);
|
||||||
g_source_set_name_by_id (tree_view->priv->typeselect_flush_timeout, "[gtk+] gtk_tree_view_search_entry_flush_timeout");
|
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-in event */
|
||||||
send_focus_change (tree_view->priv->search_entry, device, TRUE);
|
send_focus_change (tree_view->priv->search_entry, device, TRUE);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user