-
-/* completion */
-static gint
-gtk_entry_completion_timeout (gpointer data)
-{
- GtkEntryCompletion *completion = GTK_ENTRY_COMPLETION (data);
- GtkEntryPrivate *completion_entry_priv = GTK_ENTRY (completion->priv->entry)->priv;
-
- completion->priv->completion_timeout = 0;
-
- if (completion->priv->filter_model &&
- g_utf8_strlen (gtk_entry_get_text (GTK_ENTRY (completion->priv->entry)), -1)
- >= completion->priv->minimum_key_length)
- {
- gint matches;
- gint actions;
- GtkTreeSelection *s;
- gboolean popup_single;
-
- gtk_entry_completion_complete (completion);
- matches = gtk_tree_model_iter_n_children (GTK_TREE_MODEL (completion->priv->filter_model), NULL);
-
- gtk_tree_selection_unselect_all (gtk_tree_view_get_selection (GTK_TREE_VIEW (completion->priv->tree_view)));
-
- s = gtk_tree_view_get_selection (GTK_TREE_VIEW (completion->priv->action_view));
-
- gtk_tree_selection_unselect_all (s);
-
- actions = gtk_tree_model_iter_n_children (GTK_TREE_MODEL (completion->priv->actions), NULL);
-
- g_object_get (completion, "popup-single-match", &popup_single, NULL);
- if ((matches > (popup_single ? 0: 1)) || actions > 0)
- {
- if (gtk_widget_get_visible (completion->priv->popup_window))
- _gtk_entry_completion_resize_popup (completion);
- else
- _gtk_entry_completion_popup (completion, completion_entry_priv->completion_device);
- }
- else
- _gtk_entry_completion_popdown (completion);
- }
- else if (gtk_widget_get_visible (completion->priv->popup_window))
- _gtk_entry_completion_popdown (completion);
-
- return FALSE;
-}
-
-static inline gboolean
-keyval_is_cursor_move (guint keyval)
-{
- if (keyval == GDK_KEY_Up || keyval == GDK_KEY_KP_Up)
- return TRUE;
-
- if (keyval == GDK_KEY_Down || keyval == GDK_KEY_KP_Down)
- return TRUE;
-
- if (keyval == GDK_KEY_Page_Up)
- return TRUE;
-
- if (keyval == GDK_KEY_Page_Down)
- return TRUE;
-
- return FALSE;
-}
-
-static gboolean
-gtk_entry_completion_key_press (GtkWidget *widget,
- GdkEventKey *event,
- gpointer user_data)
-{
- gint matches, actions = 0;
- GtkEntryCompletion *completion = GTK_ENTRY_COMPLETION (user_data);
-
- if (!gtk_widget_get_mapped (completion->priv->popup_window))
- return FALSE;
-
- matches = gtk_tree_model_iter_n_children (GTK_TREE_MODEL (completion->priv->filter_model), NULL);
-
- if (completion->priv->actions)
- actions = gtk_tree_model_iter_n_children (GTK_TREE_MODEL (completion->priv->actions), NULL);
-
- if (keyval_is_cursor_move (event->keyval))
- {
- GtkTreePath *path = NULL;
-
- if (event->keyval == GDK_KEY_Up || event->keyval == GDK_KEY_KP_Up)
- {
- if (completion->priv->current_selected < 0)
- completion->priv->current_selected = matches + actions - 1;
- else
- completion->priv->current_selected--;
- }
- else if (event->keyval == GDK_KEY_Down || event->keyval == GDK_KEY_KP_Down)
- {
- if (completion->priv->current_selected < matches + actions - 1)
- completion->priv->current_selected++;
- else
- completion->priv->current_selected = -1;
- }
- else if (event->keyval == GDK_KEY_Page_Up)
- {
- if (completion->priv->current_selected < 0)
- completion->priv->current_selected = matches + actions - 1;
- else if (completion->priv->current_selected == 0)
- completion->priv->current_selected = -1;
- else if (completion->priv->current_selected < matches)
- {
- completion->priv->current_selected -= 14;
- if (completion->priv->current_selected < 0)
- completion->priv->current_selected = 0;
- }
- else
- {
- completion->priv->current_selected -= 14;
- if (completion->priv->current_selected < matches - 1)
- completion->priv->current_selected = matches - 1;
- }
- }
- else if (event->keyval == GDK_KEY_Page_Down)
- {
- if (completion->priv->current_selected < 0)
- completion->priv->current_selected = 0;
- else if (completion->priv->current_selected < matches - 1)
- {
- completion->priv->current_selected += 14;
- if (completion->priv->current_selected > matches - 1)
- completion->priv->current_selected = matches - 1;
- }
- else if (completion->priv->current_selected == matches + actions - 1)
- {
- completion->priv->current_selected = -1;
- }
- else
- {
- completion->priv->current_selected += 14;
- if (completion->priv->current_selected > matches + actions - 1)
- completion->priv->current_selected = matches + actions - 1;
- }
- }
-
- if (completion->priv->current_selected < 0)
- {
- 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)));
-
- if (completion->priv->inline_selection &&
- completion->priv->completion_prefix)
- {
- gtk_entry_set_text (GTK_ENTRY (completion->priv->entry),
- completion->priv->completion_prefix);
- gtk_editable_set_position (GTK_EDITABLE (widget), -1);
- }
- }
- else if (completion->priv->current_selected < matches)
- {
- gtk_tree_selection_unselect_all (gtk_tree_view_get_selection (GTK_TREE_VIEW (completion->priv->action_view)));
-
- path = gtk_tree_path_new_from_indices (completion->priv->current_selected, -1);
- gtk_tree_view_set_cursor (GTK_TREE_VIEW (completion->priv->tree_view),
- path, NULL, FALSE);
-
- if (completion->priv->inline_selection)
- {
-
- GtkTreeIter iter;
- GtkTreeIter child_iter;
- GtkTreeModel *model = NULL;
- GtkTreeSelection *sel;
- gboolean entry_set;
-
- sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (completion->priv->tree_view));
- if (!gtk_tree_selection_get_selected (sel, &model, &iter))
- return FALSE;
-
- gtk_tree_model_filter_convert_iter_to_child_iter (GTK_TREE_MODEL_FILTER (model), &child_iter, &iter);
- model = gtk_tree_model_filter_get_model (GTK_TREE_MODEL_FILTER (model));
-
- if (completion->priv->completion_prefix == NULL)
- completion->priv->completion_prefix = g_strdup (gtk_entry_get_text (GTK_ENTRY (completion->priv->entry)));
-
- g_signal_emit_by_name (completion, "cursor-on-match", model,
- &child_iter, &entry_set);
- }
- }
- else if (completion->priv->current_selected - matches >= 0)
- {
- gtk_tree_selection_unselect_all (gtk_tree_view_get_selection (GTK_TREE_VIEW (completion->priv->tree_view)));
-
- path = gtk_tree_path_new_from_indices (completion->priv->current_selected - matches, -1);
- gtk_tree_view_set_cursor (GTK_TREE_VIEW (completion->priv->action_view),
- path, NULL, FALSE);
-
- if (completion->priv->inline_selection &&
- completion->priv->completion_prefix)
- {
- gtk_entry_set_text (GTK_ENTRY (completion->priv->entry),
- completion->priv->completion_prefix);
- gtk_editable_set_position (GTK_EDITABLE (widget), -1);
- }
- }
-
- gtk_tree_path_free (path);
-
- return TRUE;
- }
- else if (event->keyval == GDK_KEY_Escape ||
- event->keyval == GDK_KEY_Left ||
- event->keyval == GDK_KEY_KP_Left ||
- event->keyval == GDK_KEY_Right ||
- event->keyval == GDK_KEY_KP_Right)
- {
- gboolean retval = TRUE;
-
- _gtk_entry_reset_im_context (GTK_ENTRY (widget));
- _gtk_entry_completion_popdown (completion);
-
- if (completion->priv->current_selected < 0)
- {
- retval = FALSE;
- goto keypress_completion_out;
- }
- else if (completion->priv->inline_selection)
- {
- /* Escape rejects the tentative completion */
- if (event->keyval == GDK_KEY_Escape)
- {
- if (completion->priv->completion_prefix)
- gtk_entry_set_text (GTK_ENTRY (completion->priv->entry),
- completion->priv->completion_prefix);
- else
- gtk_entry_set_text (GTK_ENTRY (completion->priv->entry), "");
- }
-
- /* Move the cursor to the end for Right/Esc, to the
- beginning for Left */
- if (event->keyval == GDK_KEY_Right ||
- event->keyval == GDK_KEY_KP_Right ||
- event->keyval == GDK_KEY_Escape)
- gtk_editable_set_position (GTK_EDITABLE (widget), -1);
- else
- gtk_editable_set_position (GTK_EDITABLE (widget), 0);
- }
-
-keypress_completion_out:
- if (completion->priv->inline_selection)
- {
- g_free (completion->priv->completion_prefix);
- completion->priv->completion_prefix = NULL;
- }
-
- return retval;
- }
- else if (event->keyval == GDK_KEY_Tab ||
- event->keyval == GDK_KEY_KP_Tab ||
- event->keyval == GDK_KEY_ISO_Left_Tab)
- {
- GtkDirectionType dir = event->keyval == GDK_KEY_ISO_Left_Tab ?
- GTK_DIR_TAB_BACKWARD : GTK_DIR_TAB_FORWARD;
-
- _gtk_entry_reset_im_context (GTK_ENTRY (widget));
- _gtk_entry_completion_popdown (completion);
-
- g_free (completion->priv->completion_prefix);
- completion->priv->completion_prefix = NULL;
-
- gtk_widget_child_focus (gtk_widget_get_toplevel (widget), dir);
-
- return TRUE;
- }
- else if (event->keyval == GDK_KEY_ISO_Enter ||
- event->keyval == GDK_KEY_KP_Enter ||
- event->keyval == GDK_KEY_Return)
- {
- GtkTreeIter iter;
- GtkTreeModel *model = NULL;
- GtkTreeModel *child_model;
- GtkTreeIter child_iter;
- GtkTreeSelection *sel;
- gboolean retval = TRUE;
-
- _gtk_entry_reset_im_context (GTK_ENTRY (widget));
- _gtk_entry_completion_popdown (completion);
-
- if (completion->priv->current_selected < matches)
- {
- gboolean entry_set;
-
- sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (completion->priv->tree_view));
- if (gtk_tree_selection_get_selected (sel, &model, &iter))
- {
- gtk_tree_model_filter_convert_iter_to_child_iter (GTK_TREE_MODEL_FILTER (model), &child_iter, &iter);
- child_model = gtk_tree_model_filter_get_model (GTK_TREE_MODEL_FILTER (model));
- g_signal_handler_block (widget, completion->priv->changed_id);
- g_signal_emit_by_name (completion, "match-selected",
- child_model, &child_iter, &entry_set);
- g_signal_handler_unblock (widget, completion->priv->changed_id);
-
- if (!entry_set)
- {
- gchar *str = NULL;
-
- gtk_tree_model_get (model, &iter,
- completion->priv->text_column, &str,
- -1);
-
- gtk_entry_set_text (GTK_ENTRY (widget), str);
-
- /* move the cursor to the end */
- gtk_editable_set_position (GTK_EDITABLE (widget), -1);
-
- g_free (str);
- }
- }
- else
- retval = FALSE;
- }
- else if (completion->priv->current_selected - matches >= 0)
- {
- sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (completion->priv->action_view));
- if (gtk_tree_selection_get_selected (sel, &model, &iter))
- {
- GtkTreePath *path;
-
- path = gtk_tree_path_new_from_indices (completion->priv->current_selected - matches, -1);
- g_signal_emit_by_name (completion, "action-activated",
- gtk_tree_path_get_indices (path)[0]);
- gtk_tree_path_free (path);
- }
- else
- retval = FALSE;
- }
-
- g_free (completion->priv->completion_prefix);
- completion->priv->completion_prefix = NULL;
-
- return retval;
- }
-
- return FALSE;
-}
-
-static void
-gtk_entry_completion_changed (GtkWidget *widget,
- gpointer user_data)
-{
- GtkEntryCompletion *completion = GTK_ENTRY_COMPLETION (user_data);
- GtkEntry *entry = GTK_ENTRY (widget);
- GtkEntryPrivate *priv = entry->priv;
- GdkDevice *device;
-
- /* (re)install completion timeout */
- if (completion->priv->completion_timeout)
- g_source_remove (completion->priv->completion_timeout);
-
- if (!gtk_entry_get_text (entry))
- return;
-
- /* no need to normalize for this test */
- if (completion->priv->minimum_key_length > 0 &&
- strcmp ("", gtk_entry_get_text (entry)) == 0)
- {
- if (gtk_widget_get_visible (completion->priv->popup_window))
- _gtk_entry_completion_popdown (completion);
- return;
- }
-
- device = gtk_get_current_event_device ();
-
- if (device && gdk_device_get_source (device) == GDK_SOURCE_KEYBOARD)
- device = gdk_device_get_associated_device (device);
-
- if (device)
- priv->completion_device = device;
-
- completion->priv->completion_timeout =
- gdk_threads_add_timeout (COMPLETION_TIMEOUT,
- gtk_entry_completion_timeout,
- completion);
-}
-
-static gboolean
-check_completion_callback (GtkEntryCompletion *completion)
-{
- completion->priv->check_completion_idle = NULL;
-
- gtk_entry_completion_complete (completion);
- gtk_entry_completion_insert_prefix (completion);
-
- return FALSE;
-}
-
-static void
-clear_completion_callback (GtkEntry *entry,
- GParamSpec *pspec)
-{
- if (pspec->name == I_("cursor-position") ||
- pspec->name == I_("selection-bound"))
- {
- GtkEntryCompletion *completion = gtk_entry_get_completion (entry);
-
- completion->priv->has_completion = FALSE;
- }
-}
-
-static gboolean
-accept_completion_callback (GtkEntry *entry)
-{
- GtkEntryCompletion *completion = gtk_entry_get_completion (entry);
-
- if (completion->priv->has_completion)
- gtk_editable_set_position (GTK_EDITABLE (entry),
- gtk_entry_buffer_get_length (get_buffer (entry)));
-
- return FALSE;
-}
-
-static void
-completion_insert_text_callback (GtkEntry *entry,
- const gchar *text,
- gint length,
- gint position,
- GtkEntryCompletion *completion)
-{
- /* idle to update the selection based on the file list */
- if (completion->priv->check_completion_idle == NULL)
- {
- completion->priv->check_completion_idle = g_idle_source_new ();
- g_source_set_priority (completion->priv->check_completion_idle, G_PRIORITY_HIGH);
- g_source_set_closure (completion->priv->check_completion_idle,
- g_cclosure_new_object (G_CALLBACK (check_completion_callback),
- G_OBJECT (completion)));
- g_source_attach (completion->priv->check_completion_idle, NULL);
- }
-}
-
-static void
-completion_changed (GtkEntryCompletion *completion,
- GParamSpec *pspec,
- gpointer data)
-{
- GtkEntry *entry = GTK_ENTRY (data);
-
- if (pspec->name == I_("popup-completion") ||
- pspec->name == I_("inline-completion"))
- {
- disconnect_completion_signals (entry, completion);
- connect_completion_signals (entry, completion);
- }
-}
-
-static void
-disconnect_completion_signals (GtkEntry *entry,
- GtkEntryCompletion *completion)
-{
- g_signal_handlers_disconnect_by_func (completion,
- G_CALLBACK (completion_changed), entry);
- if (completion->priv->changed_id > 0 &&
- g_signal_handler_is_connected (entry, completion->priv->changed_id))
- {
- g_signal_handler_disconnect (entry, completion->priv->changed_id);
- completion->priv->changed_id = 0;
- }
- g_signal_handlers_disconnect_by_func (entry,
- G_CALLBACK (gtk_entry_completion_key_press), completion);
- if (completion->priv->insert_text_id > 0 &&
- g_signal_handler_is_connected (entry, completion->priv->insert_text_id))
- {
- g_signal_handler_disconnect (entry, completion->priv->insert_text_id);
- completion->priv->insert_text_id = 0;
- }
- g_signal_handlers_disconnect_by_func (entry,
- G_CALLBACK (completion_insert_text_callback), completion);
- g_signal_handlers_disconnect_by_func (entry,
- G_CALLBACK (clear_completion_callback), completion);
- g_signal_handlers_disconnect_by_func (entry,
- G_CALLBACK (accept_completion_callback), completion);
-}
-
-static void
-connect_completion_signals (GtkEntry *entry,
- GtkEntryCompletion *completion)
-{
- if (completion->priv->popup_completion)
- {
- completion->priv->changed_id =
- g_signal_connect (entry, "changed",
- G_CALLBACK (gtk_entry_completion_changed), completion);
- g_signal_connect (entry, "key-press-event",
- G_CALLBACK (gtk_entry_completion_key_press), completion);
- }
-
- if (completion->priv->inline_completion)
- {
- completion->priv->insert_text_id =
- g_signal_connect (entry, "insert-text",
- G_CALLBACK (completion_insert_text_callback), completion);
- g_signal_connect (entry, "notify",
- G_CALLBACK (clear_completion_callback), completion);
- g_signal_connect (entry, "activate",
- G_CALLBACK (accept_completion_callback), completion);
- g_signal_connect (entry, "focus-out-event",
- G_CALLBACK (accept_completion_callback), completion);
- }
-
- g_signal_connect (completion, "notify",
- G_CALLBACK (completion_changed), entry);
-}
-