]> Pileus Git - ~andy/gtk/blob - gtk/gtkentrycompletion.c
Merge branch 'master' into broadway2
[~andy/gtk] / gtk / gtkentrycompletion.c
1 /* gtkentrycompletion.c
2  * Copyright (C) 2003  Kristian Rietveld  <kris@gtk.org>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 /**
21  * SECTION:gtkentrycompletion
22  * @Short_description: Completion functionality for GtkEntry
23  * @Title: GtkEntryCompletion
24  *
25  * #GtkEntryCompletion is an auxiliary object to be used in conjunction with
26  * #GtkEntry to provide the completion functionality. It implements the
27  * #GtkCellLayout interface, to allow the user to add extra cells to the
28  * #GtkTreeView with completion matches.
29  *
30  * "Completion functionality" means that when the user modifies the text
31  * in the entry, #GtkEntryCompletion checks which rows in the model match
32  * the current content of the entry, and displays a list of matches.
33  * By default, the matching is done by comparing the entry text
34  * case-insensitively against the text column of the model (see
35  * gtk_entry_completion_set_text_column()), but this can be overridden
36  * with a custom match function (see gtk_entry_completion_set_match_func()).
37  *
38  * When the user selects a completion, the content of the entry is
39  * updated. By default, the content of the entry is replaced by the
40  * text column of the model, but this can be overridden by connecting
41  * to the #GtkEntryCompletion::match-selected signal and updating the
42  * entry in the signal handler. Note that you should return %TRUE from
43  * the signal handler to suppress the default behaviour.
44  *
45  * To add completion functionality to an entry, use gtk_entry_set_completion().
46  *
47  * In addition to regular completion matches, which will be inserted into the
48  * entry when they are selected, #GtkEntryCompletion also allows to display
49  * "actions" in the popup window. Their appearance is similar to menuitems,
50  * to differentiate them clearly from completion strings. When an action is
51  * selected, the #GtkEntryCompletion::action-activated signal is emitted.
52  */
53
54 #include "config.h"
55
56 #include "gtkentrycompletion.h"
57
58 #include "gtkentryprivate.h"
59 #include "gtkcelllayout.h"
60 #include "gtkcellareabox.h"
61
62 #include "gtkintl.h"
63 #include "gtkcellrenderertext.h"
64 #include "gtkframe.h"
65 #include "gtktreeselection.h"
66 #include "gtktreeview.h"
67 #include "gtkscrolledwindow.h"
68 #include "gtksizerequest.h"
69 #include "gtkvbox.h"
70 #include "gtkwindow.h"
71 #include "gtkentry.h"
72 #include "gtkmainprivate.h"
73 #include "gtkmarshalers.h"
74
75 #include "gtkprivate.h"
76
77 #include <string.h>
78
79
80 /* signals */
81 enum
82 {
83   INSERT_PREFIX,
84   MATCH_SELECTED,
85   ACTION_ACTIVATED,
86   CURSOR_ON_MATCH,
87   LAST_SIGNAL
88 };
89
90 /* properties */
91 enum
92 {
93   PROP_0,
94   PROP_MODEL,
95   PROP_MINIMUM_KEY_LENGTH,
96   PROP_TEXT_COLUMN,
97   PROP_INLINE_COMPLETION,
98   PROP_POPUP_COMPLETION,
99   PROP_POPUP_SET_WIDTH,
100   PROP_POPUP_SINGLE_MATCH,
101   PROP_INLINE_SELECTION,
102   PROP_CELL_AREA
103 };
104
105
106 static void     gtk_entry_completion_cell_layout_init    (GtkCellLayoutIface      *iface);
107 static GtkCellArea* gtk_entry_completion_get_area        (GtkCellLayout           *cell_layout);
108
109 static GObject *gtk_entry_completion_constructor         (GType                    type,
110                                                           guint                    n_construct_properties,
111                                                           GObjectConstructParam   *construct_properties);
112 static void     gtk_entry_completion_set_property        (GObject      *object,
113                                                           guint         prop_id,
114                                                           const GValue *value,
115                                                           GParamSpec   *pspec);
116 static void     gtk_entry_completion_get_property        (GObject      *object,
117                                                           guint         prop_id,
118                                                           GValue       *value,
119                                                           GParamSpec   *pspec);
120 static void     gtk_entry_completion_finalize            (GObject      *object);
121 static void     gtk_entry_completion_dispose             (GObject      *object);
122
123 static gboolean gtk_entry_completion_visible_func        (GtkTreeModel       *model,
124                                                           GtkTreeIter        *iter,
125                                                           gpointer            data);
126 static gboolean gtk_entry_completion_popup_key_event     (GtkWidget          *widget,
127                                                           GdkEventKey        *event,
128                                                           gpointer            user_data);
129 static gboolean gtk_entry_completion_popup_button_press  (GtkWidget          *widget,
130                                                           GdkEventButton     *event,
131                                                           gpointer            user_data);
132 static gboolean gtk_entry_completion_list_button_press   (GtkWidget          *widget,
133                                                           GdkEventButton     *event,
134                                                           gpointer            user_data);
135 static gboolean gtk_entry_completion_action_button_press (GtkWidget          *widget,
136                                                           GdkEventButton     *event,
137                                                           gpointer            user_data);
138 static void     gtk_entry_completion_selection_changed   (GtkTreeSelection   *selection,
139                                                           gpointer            data);
140 static gboolean gtk_entry_completion_list_enter_notify   (GtkWidget          *widget,
141                                                           GdkEventCrossing   *event,
142                                                           gpointer            data);
143 static gboolean gtk_entry_completion_list_motion_notify  (GtkWidget          *widget,
144                                                           GdkEventMotion     *event,
145                                                           gpointer            data);
146 static void     gtk_entry_completion_insert_action       (GtkEntryCompletion *completion,
147                                                           gint                index,
148                                                           const gchar        *string,
149                                                           gboolean            markup);
150 static void     gtk_entry_completion_action_data_func    (GtkTreeViewColumn  *tree_column,
151                                                           GtkCellRenderer    *cell,
152                                                           GtkTreeModel       *model,
153                                                           GtkTreeIter        *iter,
154                                                           gpointer            data);
155
156 static gboolean gtk_entry_completion_match_selected      (GtkEntryCompletion *completion,
157                                                           GtkTreeModel       *model,
158                                                           GtkTreeIter        *iter);
159 static gboolean gtk_entry_completion_real_insert_prefix  (GtkEntryCompletion *completion,
160                                                           const gchar        *prefix);
161 static gboolean gtk_entry_completion_cursor_on_match     (GtkEntryCompletion *completion,
162                                                           GtkTreeModel       *model,
163                                                           GtkTreeIter        *iter);
164 static gboolean gtk_entry_completion_insert_completion   (GtkEntryCompletion *completion,
165                                                           GtkTreeModel       *model,
166                                                           GtkTreeIter        *iter);
167 static void     gtk_entry_completion_insert_completion_text (GtkEntryCompletion *completion,
168                                                              const gchar *text);
169
170 static guint entry_completion_signals[LAST_SIGNAL] = { 0 };
171
172 /* GtkBuildable */
173 static void     gtk_entry_completion_buildable_init      (GtkBuildableIface  *iface);
174
175 G_DEFINE_TYPE_WITH_CODE (GtkEntryCompletion, gtk_entry_completion, G_TYPE_OBJECT,
176                          G_IMPLEMENT_INTERFACE (GTK_TYPE_CELL_LAYOUT,
177                                                 gtk_entry_completion_cell_layout_init)
178                          G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
179                                                 gtk_entry_completion_buildable_init))
180
181
182 static void
183 gtk_entry_completion_class_init (GtkEntryCompletionClass *klass)
184 {
185   GObjectClass *object_class;
186
187   object_class = (GObjectClass *)klass;
188
189   object_class->constructor = gtk_entry_completion_constructor;
190   object_class->set_property = gtk_entry_completion_set_property;
191   object_class->get_property = gtk_entry_completion_get_property;
192   object_class->dispose = gtk_entry_completion_dispose;
193   object_class->finalize = gtk_entry_completion_finalize;
194
195   klass->match_selected = gtk_entry_completion_match_selected;
196   klass->insert_prefix = gtk_entry_completion_real_insert_prefix;
197   klass->cursor_on_match = gtk_entry_completion_cursor_on_match;
198
199   /**
200    * GtkEntryCompletion::insert-prefix:
201    * @widget: the object which received the signal
202    * @prefix: the common prefix of all possible completions
203    *
204    * Gets emitted when the inline autocompletion is triggered.
205    * The default behaviour is to make the entry display the
206    * whole prefix and select the newly inserted part.
207    *
208    * Applications may connect to this signal in order to insert only a
209    * smaller part of the @prefix into the entry - e.g. the entry used in
210    * the #GtkFileChooser inserts only the part of the prefix up to the
211    * next '/'.
212    *
213    * Return value: %TRUE if the signal has been handled
214    *
215    * Since: 2.6
216    */
217   entry_completion_signals[INSERT_PREFIX] =
218     g_signal_new (I_("insert-prefix"),
219                   G_TYPE_FROM_CLASS (klass),
220                   G_SIGNAL_RUN_LAST,
221                   G_STRUCT_OFFSET (GtkEntryCompletionClass, insert_prefix),
222                   _gtk_boolean_handled_accumulator, NULL,
223                   _gtk_marshal_BOOLEAN__STRING,
224                   G_TYPE_BOOLEAN, 1,
225                   G_TYPE_STRING);
226
227   /**
228    * GtkEntryCompletion::match-selected:
229    * @widget: the object which received the signal
230    * @model: the #GtkTreeModel containing the matches
231    * @iter: a #GtkTreeIter positioned at the selected match
232    *
233    * Gets emitted when a match from the list is selected.
234    * The default behaviour is to replace the contents of the
235    * entry with the contents of the text column in the row
236    * pointed to by @iter.
237    *
238    * Return value: %TRUE if the signal has been handled
239    *
240    * Since: 2.4
241    */
242   entry_completion_signals[MATCH_SELECTED] =
243     g_signal_new (I_("match-selected"),
244                   G_TYPE_FROM_CLASS (klass),
245                   G_SIGNAL_RUN_LAST,
246                   G_STRUCT_OFFSET (GtkEntryCompletionClass, match_selected),
247                   _gtk_boolean_handled_accumulator, NULL,
248                   _gtk_marshal_BOOLEAN__OBJECT_BOXED,
249                   G_TYPE_BOOLEAN, 2,
250                   GTK_TYPE_TREE_MODEL,
251                   GTK_TYPE_TREE_ITER);
252
253   /**
254    * GtkEntryCompletion::cursor-on-match:
255    * @widget: the object which received the signal
256    * @model: the #GtkTreeModel containing the matches
257    * @iter: a #GtkTreeIter positioned at the selected match
258    *
259    * Gets emitted when a match from the cursor is on a match
260    * of the list. The default behaviour is to replace the contents
261    * of the entry with the contents of the text column in the row
262    * pointed to by @iter.
263    *
264    * Return value: %TRUE if the signal has been handled
265    *
266    * Since: 2.12
267    */
268   entry_completion_signals[CURSOR_ON_MATCH] =
269     g_signal_new (I_("cursor-on-match"),
270                   G_TYPE_FROM_CLASS (klass),
271                   G_SIGNAL_RUN_LAST,
272                   G_STRUCT_OFFSET (GtkEntryCompletionClass, cursor_on_match),
273                   _gtk_boolean_handled_accumulator, NULL,
274                   _gtk_marshal_BOOLEAN__OBJECT_BOXED,
275                   G_TYPE_BOOLEAN, 2,
276                   GTK_TYPE_TREE_MODEL,
277                   GTK_TYPE_TREE_ITER);
278
279   /**
280    * GtkEntryCompletion::action-activated:
281    * @widget: the object which received the signal
282    * @index: the index of the activated action
283    *
284    * Gets emitted when an action is activated.
285    *
286    * Since: 2.4
287    */
288   entry_completion_signals[ACTION_ACTIVATED] =
289     g_signal_new (I_("action-activated"),
290                   G_TYPE_FROM_CLASS (klass),
291                   G_SIGNAL_RUN_LAST,
292                   G_STRUCT_OFFSET (GtkEntryCompletionClass, action_activated),
293                   NULL, NULL,
294                   _gtk_marshal_VOID__INT,
295                   G_TYPE_NONE, 1,
296                   G_TYPE_INT);
297
298   g_object_class_install_property (object_class,
299                                    PROP_MODEL,
300                                    g_param_spec_object ("model",
301                                                         P_("Completion Model"),
302                                                         P_("The model to find matches in"),
303                                                         GTK_TYPE_TREE_MODEL,
304                                                         GTK_PARAM_READWRITE));
305   g_object_class_install_property (object_class,
306                                    PROP_MINIMUM_KEY_LENGTH,
307                                    g_param_spec_int ("minimum-key-length",
308                                                      P_("Minimum Key Length"),
309                                                      P_("Minimum length of the search key in order to look up matches"),
310                                                      0,
311                                                      G_MAXINT,
312                                                      1,
313                                                      GTK_PARAM_READWRITE));
314   /**
315    * GtkEntryCompletion:text-column:
316    *
317    * The column of the model containing the strings.
318    * Note that the strings must be UTF-8.
319    *
320    * Since: 2.6
321    */
322   g_object_class_install_property (object_class,
323                                    PROP_TEXT_COLUMN,
324                                    g_param_spec_int ("text-column",
325                                                      P_("Text column"),
326                                                      P_("The column of the model containing the strings."),
327                                                      -1,
328                                                      G_MAXINT,
329                                                      -1,
330                                                      GTK_PARAM_READWRITE));
331
332   /**
333    * GtkEntryCompletion:inline-completion:
334    *
335    * Determines whether the common prefix of the possible completions
336    * should be inserted automatically in the entry. Note that this
337    * requires text-column to be set, even if you are using a custom
338    * match function.
339    *
340    * Since: 2.6
341    **/
342   g_object_class_install_property (object_class,
343                                    PROP_INLINE_COMPLETION,
344                                    g_param_spec_boolean ("inline-completion",
345                                                          P_("Inline completion"),
346                                                          P_("Whether the common prefix should be inserted automatically"),
347                                                          FALSE,
348                                                          GTK_PARAM_READWRITE));
349   /**
350    * GtkEntryCompletion:popup-completion:
351    *
352    * Determines whether the possible completions should be
353    * shown in a popup window.
354    *
355    * Since: 2.6
356    **/
357   g_object_class_install_property (object_class,
358                                    PROP_POPUP_COMPLETION,
359                                    g_param_spec_boolean ("popup-completion",
360                                                          P_("Popup completion"),
361                                                          P_("Whether the completions should be shown in a popup window"),
362                                                          TRUE,
363                                                          GTK_PARAM_READWRITE));
364
365   /**
366    * GtkEntryCompletion:popup-set-width:
367    *
368    * Determines whether the completions popup window will be
369    * resized to the width of the entry.
370    *
371    * Since: 2.8
372    */
373   g_object_class_install_property (object_class,
374                                    PROP_POPUP_SET_WIDTH,
375                                    g_param_spec_boolean ("popup-set-width",
376                                                          P_("Popup set width"),
377                                                          P_("If TRUE, the popup window will have the same size as the entry"),
378                                                          TRUE,
379                                                          GTK_PARAM_READWRITE));
380
381   /**
382    * GtkEntryCompletion:popup-single-match:
383    *
384    * Determines whether the completions popup window will shown
385    * for a single possible completion. You probably want to set
386    * this to %FALSE if you are using
387    * <link linkend="GtkEntryCompletion--inline-completion">inline
388    * completion</link>.
389    *
390    * Since: 2.8
391    */
392   g_object_class_install_property (object_class,
393                                    PROP_POPUP_SINGLE_MATCH,
394                                    g_param_spec_boolean ("popup-single-match",
395                                                          P_("Popup single match"),
396                                                          P_("If TRUE, the popup window will appear for a single match."),
397                                                          TRUE,
398                                                          GTK_PARAM_READWRITE));
399   /**
400    * GtkEntryCompletion:inline-selection:
401    *
402    * Determines whether the possible completions on the popup
403    * will appear in the entry as you navigate through them.
404    *
405    * Since: 2.12
406    */
407   g_object_class_install_property (object_class,
408                                    PROP_INLINE_SELECTION,
409                                    g_param_spec_boolean ("inline-selection",
410                                                          P_("Inline selection"),
411                                                          P_("Your description here"),
412                                                          FALSE,
413                                                          GTK_PARAM_READWRITE));
414
415
416   /**
417    * GtkEntryCompletion:cell-area:
418    *
419    * The #GtkCellArea used to layout cell renderers in the treeview column.
420    *
421    * Since: 3.0
422    */
423   g_object_class_install_property (object_class,
424                                    PROP_CELL_AREA,
425                                    g_param_spec_object ("cell-area",
426                                                         P_("Cell Area"),
427                                                         P_("The GtkCellArea used to layout cells"),
428                                                         GTK_TYPE_CELL_AREA,
429                                                         GTK_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
430
431   g_type_class_add_private (object_class, sizeof (GtkEntryCompletionPrivate));
432 }
433
434
435 static void
436 gtk_entry_completion_buildable_custom_tag_end (GtkBuildable *buildable,
437                                                 GtkBuilder   *builder,
438                                                 GObject      *child,
439                                                 const gchar  *tagname,
440                                                 gpointer     *data)
441 {
442   /* Just ignore the boolean return from here */
443   _gtk_cell_layout_buildable_custom_tag_end (buildable, builder, child, tagname, data);
444 }
445
446 static void
447 gtk_entry_completion_buildable_init (GtkBuildableIface *iface)
448 {
449   iface->add_child = _gtk_cell_layout_buildable_add_child;
450   iface->custom_tag_start = _gtk_cell_layout_buildable_custom_tag_start;
451   iface->custom_tag_end = gtk_entry_completion_buildable_custom_tag_end;
452 }
453
454 static void
455 gtk_entry_completion_cell_layout_init (GtkCellLayoutIface *iface)
456 {
457   iface->get_area = gtk_entry_completion_get_area;
458 }
459
460 static void
461 gtk_entry_completion_init (GtkEntryCompletion *completion)
462 {
463   GtkEntryCompletionPrivate *priv;
464
465   /* yes, also priv, need to keep the code readable */
466   completion->priv = G_TYPE_INSTANCE_GET_PRIVATE (completion,
467                                                   GTK_TYPE_ENTRY_COMPLETION,
468                                                   GtkEntryCompletionPrivate);
469   priv = completion->priv;
470
471   priv->minimum_key_length = 1;
472   priv->text_column = -1;
473   priv->has_completion = FALSE;
474   priv->inline_completion = FALSE;
475   priv->popup_completion = TRUE;
476   priv->popup_set_width = TRUE;
477   priv->popup_single_match = TRUE;
478   priv->inline_selection = FALSE;
479
480   priv->filter_model = NULL;
481 }
482
483 static GObject *
484 gtk_entry_completion_constructor (GType                    type,
485                                   guint                    n_construct_properties,
486                                   GObjectConstructParam   *construct_properties)
487 {
488   GtkEntryCompletion        *completion;
489   GtkEntryCompletionPrivate *priv;
490   GObject                   *object;
491   GtkCellRenderer           *cell;
492   GtkTreeSelection          *sel;
493   GtkWidget                 *popup_frame;
494
495   object = G_OBJECT_CLASS (gtk_entry_completion_parent_class)->constructor
496     (type, n_construct_properties, construct_properties);
497
498   completion = (GtkEntryCompletion *) object;
499   priv       = completion->priv;
500
501   if (!priv->cell_area)
502     {
503       priv->cell_area = gtk_cell_area_box_new ();
504       g_object_ref_sink (priv->cell_area);
505     }
506
507   /* completions */
508   priv->tree_view = gtk_tree_view_new ();
509   g_signal_connect (priv->tree_view, "button-press-event",
510                     G_CALLBACK (gtk_entry_completion_list_button_press),
511                     completion);
512   g_signal_connect (priv->tree_view, "enter-notify-event",
513                     G_CALLBACK (gtk_entry_completion_list_enter_notify),
514                     completion);
515   g_signal_connect (priv->tree_view, "motion-notify-event",
516                     G_CALLBACK (gtk_entry_completion_list_motion_notify),
517                     completion);
518
519   gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (priv->tree_view), FALSE);
520   gtk_tree_view_set_hover_selection (GTK_TREE_VIEW (priv->tree_view), TRUE);
521
522   sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->tree_view));
523   gtk_tree_selection_set_mode (sel, GTK_SELECTION_SINGLE);
524   gtk_tree_selection_unselect_all (sel);
525   g_signal_connect (sel, "changed",
526                     G_CALLBACK (gtk_entry_completion_selection_changed),
527                     completion);
528   priv->first_sel_changed = TRUE;
529
530   priv->column = gtk_tree_view_column_new_with_area (priv->cell_area);
531   gtk_tree_view_append_column (GTK_TREE_VIEW (priv->tree_view), priv->column);
532
533   priv->scrolled_window = gtk_scrolled_window_new (NULL, NULL);
534   gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (priv->scrolled_window),
535                                   GTK_POLICY_NEVER,
536                                   GTK_POLICY_AUTOMATIC);
537   gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (priv->scrolled_window),
538                                        GTK_SHADOW_NONE);
539
540   /* a nasty hack to get the completions treeview to size nicely */
541   gtk_widget_set_size_request (gtk_scrolled_window_get_vscrollbar (GTK_SCROLLED_WINDOW (priv->scrolled_window)),
542                                -1, 0);
543
544   /* actions */
545   priv->actions = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_BOOLEAN);
546
547   priv->action_view =
548     gtk_tree_view_new_with_model (GTK_TREE_MODEL (priv->actions));
549   g_object_ref_sink (priv->action_view);
550   g_signal_connect (priv->action_view, "button-press-event",
551                     G_CALLBACK (gtk_entry_completion_action_button_press),
552                     completion);
553   g_signal_connect (priv->action_view, "enter-notify-event",
554                     G_CALLBACK (gtk_entry_completion_list_enter_notify),
555                     completion);
556   g_signal_connect (priv->action_view, "motion-notify-event",
557                     G_CALLBACK (gtk_entry_completion_list_motion_notify),
558                     completion);
559   gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (priv->action_view), FALSE);
560   gtk_tree_view_set_hover_selection (GTK_TREE_VIEW (priv->action_view), TRUE);
561
562   sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->action_view));
563   gtk_tree_selection_set_mode (sel, GTK_SELECTION_SINGLE);
564   gtk_tree_selection_unselect_all (sel);
565
566   cell = gtk_cell_renderer_text_new ();
567   gtk_tree_view_insert_column_with_data_func (GTK_TREE_VIEW (priv->action_view),
568                                               0, "",
569                                               cell,
570                                               gtk_entry_completion_action_data_func,
571                                               NULL,
572                                               NULL);
573
574   /* pack it all */
575   priv->popup_window = gtk_window_new (GTK_WINDOW_POPUP);
576   gtk_window_set_resizable (GTK_WINDOW (priv->popup_window), FALSE);
577   gtk_window_set_type_hint (GTK_WINDOW(priv->popup_window),
578                             GDK_WINDOW_TYPE_HINT_COMBO);
579   g_signal_connect (priv->popup_window, "key-press-event",
580                     G_CALLBACK (gtk_entry_completion_popup_key_event),
581                     completion);
582   g_signal_connect (priv->popup_window, "key-release-event",
583                     G_CALLBACK (gtk_entry_completion_popup_key_event),
584                     completion);
585   g_signal_connect (priv->popup_window, "button-press-event",
586                     G_CALLBACK (gtk_entry_completion_popup_button_press),
587                     completion);
588
589   popup_frame = gtk_frame_new (NULL);
590   gtk_frame_set_shadow_type (GTK_FRAME (popup_frame),
591                              GTK_SHADOW_ETCHED_IN);
592   gtk_widget_show (popup_frame);
593   gtk_container_add (GTK_CONTAINER (priv->popup_window), popup_frame);
594
595   priv->vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
596   gtk_container_add (GTK_CONTAINER (popup_frame), priv->vbox);
597
598   gtk_container_add (GTK_CONTAINER (priv->scrolled_window), priv->tree_view);
599   gtk_box_pack_start (GTK_BOX (priv->vbox), priv->scrolled_window,
600                       TRUE, TRUE, 0);
601
602   /* we don't want to see the action treeview when no actions have
603    * been inserted, so we pack the action treeview after the first
604    * action has been added
605    */
606
607   return object;
608 }
609
610
611 static void
612 gtk_entry_completion_set_property (GObject      *object,
613                                    guint         prop_id,
614                                    const GValue *value,
615                                    GParamSpec   *pspec)
616 {
617   GtkEntryCompletion *completion = GTK_ENTRY_COMPLETION (object);
618   GtkEntryCompletionPrivate *priv = completion->priv;
619   GtkCellArea *area;
620
621   switch (prop_id)
622     {
623       case PROP_MODEL:
624         gtk_entry_completion_set_model (completion,
625                                         g_value_get_object (value));
626         break;
627
628       case PROP_MINIMUM_KEY_LENGTH:
629         gtk_entry_completion_set_minimum_key_length (completion,
630                                                      g_value_get_int (value));
631         break;
632
633       case PROP_TEXT_COLUMN:
634         priv->text_column = g_value_get_int (value);
635         break;
636
637       case PROP_INLINE_COMPLETION:
638         priv->inline_completion = g_value_get_boolean (value);
639         break;
640
641       case PROP_POPUP_COMPLETION:
642         priv->popup_completion = g_value_get_boolean (value);
643         break;
644
645       case PROP_POPUP_SET_WIDTH:
646         priv->popup_set_width = g_value_get_boolean (value);
647         break;
648
649       case PROP_POPUP_SINGLE_MATCH:
650         priv->popup_single_match = g_value_get_boolean (value);
651         break;
652
653       case PROP_INLINE_SELECTION:
654         priv->inline_selection = g_value_get_boolean (value);
655         break;
656
657       case PROP_CELL_AREA:
658         /* Construct-only, can only be assigned once */
659         area = g_value_get_object (value);
660
661         if (area)
662           priv->cell_area = g_object_ref_sink (area);
663         break;
664
665       default:
666         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
667         break;
668     }
669 }
670
671 static void
672 gtk_entry_completion_get_property (GObject    *object,
673                                    guint       prop_id,
674                                    GValue     *value,
675                                    GParamSpec *pspec)
676 {
677   GtkEntryCompletion *completion = GTK_ENTRY_COMPLETION (object);
678
679   switch (prop_id)
680     {
681       case PROP_MODEL:
682         g_value_set_object (value,
683                             gtk_entry_completion_get_model (completion));
684         break;
685
686       case PROP_MINIMUM_KEY_LENGTH:
687         g_value_set_int (value, gtk_entry_completion_get_minimum_key_length (completion));
688         break;
689
690       case PROP_TEXT_COLUMN:
691         g_value_set_int (value, gtk_entry_completion_get_text_column (completion));
692         break;
693
694       case PROP_INLINE_COMPLETION:
695         g_value_set_boolean (value, gtk_entry_completion_get_inline_completion (completion));
696         break;
697
698       case PROP_POPUP_COMPLETION:
699         g_value_set_boolean (value, gtk_entry_completion_get_popup_completion (completion));
700         break;
701
702       case PROP_POPUP_SET_WIDTH:
703         g_value_set_boolean (value, gtk_entry_completion_get_popup_set_width (completion));
704         break;
705
706       case PROP_POPUP_SINGLE_MATCH:
707         g_value_set_boolean (value, gtk_entry_completion_get_popup_single_match (completion));
708         break;
709
710       case PROP_INLINE_SELECTION:
711         g_value_set_boolean (value, gtk_entry_completion_get_inline_selection (completion));
712         break;
713
714       case PROP_CELL_AREA:
715         g_value_set_object (value, completion->priv->cell_area);
716         break;
717
718       default:
719         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
720         break;
721     }
722 }
723
724 static void
725 gtk_entry_completion_finalize (GObject *object)
726 {
727   GtkEntryCompletion *completion = GTK_ENTRY_COMPLETION (object);
728   GtkEntryCompletionPrivate *priv = completion->priv;
729
730   g_free (priv->case_normalized_key);
731   g_free (priv->completion_prefix);
732
733   if (priv->match_notify)
734     (* priv->match_notify) (priv->match_data);
735
736   G_OBJECT_CLASS (gtk_entry_completion_parent_class)->finalize (object);
737 }
738
739 static void
740 gtk_entry_completion_dispose (GObject *object)
741 {
742   GtkEntryCompletion *completion = GTK_ENTRY_COMPLETION (object);
743   GtkEntryCompletionPrivate *priv = completion->priv;
744
745   if (priv->tree_view)
746     {
747       gtk_widget_destroy (priv->tree_view);
748       priv->tree_view = NULL;
749     }
750
751   if (priv->entry)
752     gtk_entry_set_completion (GTK_ENTRY (priv->entry), NULL);
753
754   if (priv->actions)
755     {
756       g_object_unref (priv->actions);
757       priv->actions = NULL;
758     }
759
760   if (priv->action_view)
761     {
762       g_object_unref (priv->action_view);
763       priv->action_view = NULL;
764     }
765
766   if (priv->popup_window)
767     {
768       gtk_widget_destroy (priv->popup_window);
769       priv->popup_window = NULL;
770     }
771
772   if (priv->cell_area)
773     {
774       g_object_unref (priv->cell_area);
775       priv->cell_area = NULL;
776     }
777
778   G_OBJECT_CLASS (gtk_entry_completion_parent_class)->dispose (object);
779 }
780
781 /* implement cell layout interface (only need to return the underlying cell area) */
782 static GtkCellArea*
783 gtk_entry_completion_get_area (GtkCellLayout *cell_layout)
784 {
785   GtkEntryCompletionPrivate *priv;
786
787   priv = GTK_ENTRY_COMPLETION (cell_layout)->priv;
788
789   return priv->cell_area;
790 }
791
792 /* all those callbacks */
793 static gboolean
794 gtk_entry_completion_default_completion_func (GtkEntryCompletion *completion,
795                                               const gchar        *key,
796                                               GtkTreeIter        *iter,
797                                               gpointer            user_data)
798 {
799   gchar *item = NULL;
800   gchar *normalized_string;
801   gchar *case_normalized_string;
802
803   gboolean ret = FALSE;
804
805   GtkTreeModel *model;
806
807   model = gtk_tree_model_filter_get_model (completion->priv->filter_model);
808
809   g_return_val_if_fail (gtk_tree_model_get_column_type (model, completion->priv->text_column) == G_TYPE_STRING,
810                         FALSE);
811
812   gtk_tree_model_get (model, iter,
813                       completion->priv->text_column, &item,
814                       -1);
815
816   if (item != NULL)
817     {
818       normalized_string = g_utf8_normalize (item, -1, G_NORMALIZE_ALL);
819
820       if (normalized_string != NULL)
821         {
822           case_normalized_string = g_utf8_casefold (normalized_string, -1);
823
824           if (!strncmp (key, case_normalized_string, strlen (key)))
825             ret = TRUE;
826
827           g_free (case_normalized_string);
828         }
829       g_free (normalized_string);
830     }
831   g_free (item);
832
833   return ret;
834 }
835
836 static gboolean
837 gtk_entry_completion_visible_func (GtkTreeModel *model,
838                                    GtkTreeIter  *iter,
839                                    gpointer      data)
840 {
841   gboolean ret = FALSE;
842
843   GtkEntryCompletion *completion = GTK_ENTRY_COMPLETION (data);
844
845   if (!completion->priv->case_normalized_key)
846     return ret;
847
848   if (completion->priv->match_func)
849     ret = (* completion->priv->match_func) (completion,
850                                             completion->priv->case_normalized_key,
851                                             iter,
852                                             completion->priv->match_data);
853   else if (completion->priv->text_column >= 0)
854     ret = gtk_entry_completion_default_completion_func (completion,
855                                                         completion->priv->case_normalized_key,
856                                                         iter,
857                                                         NULL);
858
859   return ret;
860 }
861
862 static gboolean
863 gtk_entry_completion_popup_key_event (GtkWidget   *widget,
864                                       GdkEventKey *event,
865                                       gpointer     user_data)
866 {
867   GtkEntryCompletion *completion = GTK_ENTRY_COMPLETION (user_data);
868
869   if (!gtk_widget_get_mapped (completion->priv->popup_window))
870     return FALSE;
871
872   /* propagate event to the entry */
873   gtk_widget_event (completion->priv->entry, (GdkEvent *)event);
874
875   return TRUE;
876 }
877
878 static gboolean
879 gtk_entry_completion_popup_button_press (GtkWidget      *widget,
880                                          GdkEventButton *event,
881                                          gpointer        user_data)
882 {
883   GtkEntryCompletion *completion = GTK_ENTRY_COMPLETION (user_data);
884
885   if (!gtk_widget_get_mapped (completion->priv->popup_window))
886     return FALSE;
887
888   /* if we come here, it's usually time to popdown */
889   _gtk_entry_completion_popdown (completion);
890
891   return TRUE;
892 }
893
894 static gboolean
895 gtk_entry_completion_list_button_press (GtkWidget      *widget,
896                                         GdkEventButton *event,
897                                         gpointer        user_data)
898 {
899   GtkEntryCompletion *completion = GTK_ENTRY_COMPLETION (user_data);
900   GtkTreePath *path = NULL;
901
902   if (!gtk_widget_get_mapped (completion->priv->popup_window))
903     return FALSE;
904
905   if (gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (widget),
906                                      event->x, event->y,
907                                      &path, NULL, NULL, NULL))
908     {
909       GtkTreeIter iter;
910       gboolean entry_set;
911       GtkTreeModel *model;
912       GtkTreeIter child_iter;
913
914       gtk_tree_model_get_iter (GTK_TREE_MODEL (completion->priv->filter_model),
915                                &iter, path);
916       gtk_tree_path_free (path);
917       gtk_tree_model_filter_convert_iter_to_child_iter (completion->priv->filter_model,
918                                                         &child_iter,
919                                                         &iter);
920       model = gtk_tree_model_filter_get_model (completion->priv->filter_model);
921
922       g_signal_handler_block (completion->priv->entry,
923                               completion->priv->changed_id);
924       g_signal_emit (completion, entry_completion_signals[MATCH_SELECTED],
925                      0, model, &child_iter, &entry_set);
926       g_signal_handler_unblock (completion->priv->entry,
927                                 completion->priv->changed_id);
928
929       _gtk_entry_completion_popdown (completion);
930
931       return TRUE;
932     }
933
934   return FALSE;
935 }
936
937 static gboolean
938 gtk_entry_completion_action_button_press (GtkWidget      *widget,
939                                           GdkEventButton *event,
940                                           gpointer        user_data)
941 {
942   GtkEntryCompletion *completion = GTK_ENTRY_COMPLETION (user_data);
943   GtkTreePath *path = NULL;
944
945   if (!gtk_widget_get_mapped (completion->priv->popup_window))
946     return FALSE;
947
948   _gtk_entry_reset_im_context (GTK_ENTRY (completion->priv->entry));
949
950   if (gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (widget),
951                                      event->x, event->y,
952                                      &path, NULL, NULL, NULL))
953     {
954       g_signal_emit (completion, entry_completion_signals[ACTION_ACTIVATED],
955                      0, gtk_tree_path_get_indices (path)[0]);
956       gtk_tree_path_free (path);
957
958       _gtk_entry_completion_popdown (completion);
959       return TRUE;
960     }
961
962   return FALSE;
963 }
964
965 static void
966 gtk_entry_completion_action_data_func (GtkTreeViewColumn *tree_column,
967                                        GtkCellRenderer   *cell,
968                                        GtkTreeModel      *model,
969                                        GtkTreeIter       *iter,
970                                        gpointer           data)
971 {
972   gchar *string = NULL;
973   gboolean markup;
974
975   gtk_tree_model_get (model, iter,
976                       0, &string,
977                       1, &markup,
978                       -1);
979
980   if (!string)
981     return;
982
983   if (markup)
984     g_object_set (cell,
985                   "text", NULL,
986                   "markup", string,
987                   NULL);
988   else
989     g_object_set (cell,
990                   "markup", NULL,
991                   "text", string,
992                   NULL);
993
994   g_free (string);
995 }
996
997 static void
998 gtk_entry_completion_selection_changed (GtkTreeSelection *selection,
999                                         gpointer          data)
1000 {
1001   GtkEntryCompletion *completion = GTK_ENTRY_COMPLETION (data);
1002
1003   if (completion->priv->first_sel_changed)
1004     {
1005       completion->priv->first_sel_changed = FALSE;
1006       if (gtk_widget_is_focus (completion->priv->tree_view))
1007         gtk_tree_selection_unselect_all (selection);
1008     }
1009 }
1010
1011 /* public API */
1012
1013 /**
1014  * gtk_entry_completion_new:
1015  *
1016  * Creates a new #GtkEntryCompletion object.
1017  *
1018  * Return value: A newly created #GtkEntryCompletion object
1019  *
1020  * Since: 2.4
1021  */
1022 GtkEntryCompletion *
1023 gtk_entry_completion_new (void)
1024 {
1025   GtkEntryCompletion *completion;
1026
1027   completion = g_object_new (GTK_TYPE_ENTRY_COMPLETION, NULL);
1028
1029   return completion;
1030 }
1031
1032 /**
1033  * gtk_entry_completion_new_with_area:
1034  * @area: the #GtkCellArea used to layout cells
1035  *
1036  * Creates a new #GtkEntryCompletion object using the
1037  * specified @area to layout cells in the underlying
1038  * #GtkTreeViewColumn for the drop-down menu.
1039  *
1040  * Return value: A newly created #GtkEntryCompletion object
1041  *
1042  * Since: 3.0
1043  */
1044 GtkEntryCompletion *
1045 gtk_entry_completion_new_with_area (GtkCellArea *area)
1046 {
1047   GtkEntryCompletion *completion;
1048
1049   completion = g_object_new (GTK_TYPE_ENTRY_COMPLETION, "cell-area", area, NULL);
1050
1051   return completion;
1052 }
1053
1054 /**
1055  * gtk_entry_completion_get_entry:
1056  * @completion: a #GtkEntryCompletion
1057  *
1058  * Gets the entry @completion has been attached to.
1059  *
1060  * Return value: (transfer none): The entry @completion has been attached to
1061  *
1062  * Since: 2.4
1063  */
1064 GtkWidget *
1065 gtk_entry_completion_get_entry (GtkEntryCompletion *completion)
1066 {
1067   g_return_val_if_fail (GTK_IS_ENTRY_COMPLETION (completion), NULL);
1068
1069   return completion->priv->entry;
1070 }
1071
1072 /**
1073  * gtk_entry_completion_set_model:
1074  * @completion: a #GtkEntryCompletion
1075  * @model: (allow-none): the #GtkTreeModel
1076  *
1077  * Sets the model for a #GtkEntryCompletion. If @completion already has
1078  * a model set, it will remove it before setting the new model.
1079  * If model is %NULL, then it will unset the model.
1080  *
1081  * Since: 2.4
1082  */
1083 void
1084 gtk_entry_completion_set_model (GtkEntryCompletion *completion,
1085                                 GtkTreeModel       *model)
1086 {
1087   g_return_if_fail (GTK_IS_ENTRY_COMPLETION (completion));
1088   g_return_if_fail (model == NULL || GTK_IS_TREE_MODEL (model));
1089
1090   if (!model)
1091     {
1092       gtk_tree_view_set_model (GTK_TREE_VIEW (completion->priv->tree_view),
1093                                NULL);
1094       _gtk_entry_completion_popdown (completion);
1095       completion->priv->filter_model = NULL;
1096       return;
1097     }
1098
1099   /* code will unref the old filter model (if any) */
1100   completion->priv->filter_model =
1101     GTK_TREE_MODEL_FILTER (gtk_tree_model_filter_new (model, NULL));
1102   gtk_tree_model_filter_set_visible_func (completion->priv->filter_model,
1103                                           gtk_entry_completion_visible_func,
1104                                           completion,
1105                                           NULL);
1106
1107   gtk_tree_view_set_model (GTK_TREE_VIEW (completion->priv->tree_view),
1108                            GTK_TREE_MODEL (completion->priv->filter_model));
1109   g_object_unref (completion->priv->filter_model);
1110
1111   g_object_notify (G_OBJECT (completion), "model");
1112
1113   if (gtk_widget_get_visible (completion->priv->popup_window))
1114     _gtk_entry_completion_resize_popup (completion);
1115 }
1116
1117 /**
1118  * gtk_entry_completion_get_model:
1119  * @completion: a #GtkEntryCompletion
1120  *
1121  * Returns the model the #GtkEntryCompletion is using as data source.
1122  * Returns %NULL if the model is unset.
1123  *
1124  * Return value: (transfer none): A #GtkTreeModel, or %NULL if none
1125  *     is currently being used
1126  *
1127  * Since: 2.4
1128  */
1129 GtkTreeModel *
1130 gtk_entry_completion_get_model (GtkEntryCompletion *completion)
1131 {
1132   g_return_val_if_fail (GTK_IS_ENTRY_COMPLETION (completion), NULL);
1133
1134   if (!completion->priv->filter_model)
1135     return NULL;
1136
1137   return gtk_tree_model_filter_get_model (completion->priv->filter_model);
1138 }
1139
1140 /**
1141  * gtk_entry_completion_set_match_func:
1142  * @completion: a #GtkEntryCompletion
1143  * @func: the #GtkEntryCompletionMatchFunc to use
1144  * @func_data: user data for @func
1145  * @func_notify: destroy notify for @func_data.
1146  *
1147  * Sets the match function for @completion to be @func. The match function
1148  * is used to determine if a row should or should not be in the completion
1149  * list.
1150  *
1151  * Since: 2.4
1152  */
1153 void
1154 gtk_entry_completion_set_match_func (GtkEntryCompletion          *completion,
1155                                      GtkEntryCompletionMatchFunc  func,
1156                                      gpointer                     func_data,
1157                                      GDestroyNotify               func_notify)
1158 {
1159   g_return_if_fail (GTK_IS_ENTRY_COMPLETION (completion));
1160
1161   if (completion->priv->match_notify)
1162     (* completion->priv->match_notify) (completion->priv->match_data);
1163
1164   completion->priv->match_func = func;
1165   completion->priv->match_data = func_data;
1166   completion->priv->match_notify = func_notify;
1167 }
1168
1169 /**
1170  * gtk_entry_completion_set_minimum_key_length:
1171  * @completion: a #GtkEntryCompletion
1172  * @length: the minimum length of the key in order to start completing
1173  *
1174  * Requires the length of the search key for @completion to be at least
1175  * @length. This is useful for long lists, where completing using a small
1176  * key takes a lot of time and will come up with meaningless results anyway
1177  * (ie, a too large dataset).
1178  *
1179  * Since: 2.4
1180  */
1181 void
1182 gtk_entry_completion_set_minimum_key_length (GtkEntryCompletion *completion,
1183                                              gint                length)
1184 {
1185   g_return_if_fail (GTK_IS_ENTRY_COMPLETION (completion));
1186   g_return_if_fail (length >= 0);
1187
1188   if (completion->priv->minimum_key_length != length)
1189     {
1190       completion->priv->minimum_key_length = length;
1191
1192       g_object_notify (G_OBJECT (completion), "minimum-key-length");
1193     }
1194 }
1195
1196 /**
1197  * gtk_entry_completion_get_minimum_key_length:
1198  * @completion: a #GtkEntryCompletion
1199  *
1200  * Returns the minimum key length as set for @completion.
1201  *
1202  * Return value: The currently used minimum key length
1203  *
1204  * Since: 2.4
1205  */
1206 gint
1207 gtk_entry_completion_get_minimum_key_length (GtkEntryCompletion *completion)
1208 {
1209   g_return_val_if_fail (GTK_IS_ENTRY_COMPLETION (completion), 0);
1210
1211   return completion->priv->minimum_key_length;
1212 }
1213
1214 /**
1215  * gtk_entry_completion_complete:
1216  * @completion: a #GtkEntryCompletion
1217  *
1218  * Requests a completion operation, or in other words a refiltering of the
1219  * current list with completions, using the current key. The completion list
1220  * view will be updated accordingly.
1221  *
1222  * Since: 2.4
1223  */
1224 void
1225 gtk_entry_completion_complete (GtkEntryCompletion *completion)
1226 {
1227   gchar *tmp;
1228
1229   g_return_if_fail (GTK_IS_ENTRY_COMPLETION (completion));
1230
1231   if (!completion->priv->filter_model)
1232     return;
1233
1234   g_free (completion->priv->case_normalized_key);
1235
1236   tmp = g_utf8_normalize (gtk_entry_get_text (GTK_ENTRY (completion->priv->entry)),
1237                           -1, G_NORMALIZE_ALL);
1238   completion->priv->case_normalized_key = g_utf8_casefold (tmp, -1);
1239   g_free (tmp);
1240
1241   gtk_tree_model_filter_refilter (completion->priv->filter_model);
1242
1243   if (gtk_widget_get_visible (completion->priv->popup_window))
1244     _gtk_entry_completion_resize_popup (completion);
1245 }
1246
1247 static void
1248 gtk_entry_completion_insert_action (GtkEntryCompletion *completion,
1249                                     gint                index,
1250                                     const gchar        *string,
1251                                     gboolean            markup)
1252 {
1253   GtkTreeIter iter;
1254
1255   gtk_list_store_insert (completion->priv->actions, &iter, index);
1256   gtk_list_store_set (completion->priv->actions, &iter,
1257                       0, string,
1258                       1, markup,
1259                       -1);
1260
1261   if (!gtk_widget_get_parent (completion->priv->action_view))
1262     {
1263       GtkTreePath *path = gtk_tree_path_new_from_indices (0, -1);
1264
1265       gtk_tree_view_set_cursor (GTK_TREE_VIEW (completion->priv->action_view),
1266                                 path, NULL, FALSE);
1267       gtk_tree_path_free (path);
1268
1269       gtk_box_pack_start (GTK_BOX (completion->priv->vbox),
1270                           completion->priv->action_view, FALSE, FALSE, 0);
1271       gtk_widget_show (completion->priv->action_view);
1272     }
1273 }
1274
1275 /**
1276  * gtk_entry_completion_insert_action_text:
1277  * @completion: a #GtkEntryCompletion
1278  * @index_: the index of the item to insert
1279  * @text: text of the item to insert
1280  *
1281  * Inserts an action in @completion's action item list at position @index_
1282  * with text @text. If you want the action item to have markup, use
1283  * gtk_entry_completion_insert_action_markup().
1284  *
1285  * Since: 2.4
1286  */
1287 void
1288 gtk_entry_completion_insert_action_text (GtkEntryCompletion *completion,
1289                                          gint                index_,
1290                                          const gchar        *text)
1291 {
1292   g_return_if_fail (GTK_IS_ENTRY_COMPLETION (completion));
1293   g_return_if_fail (text != NULL);
1294
1295   gtk_entry_completion_insert_action (completion, index_, text, FALSE);
1296 }
1297
1298 /**
1299  * gtk_entry_completion_insert_action_markup:
1300  * @completion: a #GtkEntryCompletion
1301  * @index_: the index of the item to insert
1302  * @markup: markup of the item to insert
1303  *
1304  * Inserts an action in @completion's action item list at position @index_
1305  * with markup @markup.
1306  *
1307  * Since: 2.4
1308  */
1309 void
1310 gtk_entry_completion_insert_action_markup (GtkEntryCompletion *completion,
1311                                            gint                index_,
1312                                            const gchar        *markup)
1313 {
1314   g_return_if_fail (GTK_IS_ENTRY_COMPLETION (completion));
1315   g_return_if_fail (markup != NULL);
1316
1317   gtk_entry_completion_insert_action (completion, index_, markup, TRUE);
1318 }
1319
1320 /**
1321  * gtk_entry_completion_delete_action:
1322  * @completion: a #GtkEntryCompletion
1323  * @index_: the index of the item to delete
1324  *
1325  * Deletes the action at @index_ from @completion's action list.
1326  *
1327  * Since: 2.4
1328  */
1329 void
1330 gtk_entry_completion_delete_action (GtkEntryCompletion *completion,
1331                                     gint                index_)
1332 {
1333   GtkTreeIter iter;
1334
1335   g_return_if_fail (GTK_IS_ENTRY_COMPLETION (completion));
1336   g_return_if_fail (index_ >= 0);
1337
1338   gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (completion->priv->actions),
1339                                  &iter, NULL, index_);
1340   gtk_list_store_remove (completion->priv->actions, &iter);
1341 }
1342
1343 /**
1344  * gtk_entry_completion_set_text_column:
1345  * @completion: a #GtkEntryCompletion
1346  * @column: the column in the model of @completion to get strings from
1347  *
1348  * Convenience function for setting up the most used case of this code: a
1349  * completion list with just strings. This function will set up @completion
1350  * to have a list displaying all (and just) strings in the completion list,
1351  * and to get those strings from @column in the model of @completion.
1352  *
1353  * This functions creates and adds a #GtkCellRendererText for the selected
1354  * column. If you need to set the text column, but don't want the cell
1355  * renderer, use g_object_set() to set the #GtkEntryCompletion:text-column
1356  * property directly.
1357  *
1358  * Since: 2.4
1359  */
1360 void
1361 gtk_entry_completion_set_text_column (GtkEntryCompletion *completion,
1362                                       gint                column)
1363 {
1364   GtkCellRenderer *cell;
1365
1366   g_return_if_fail (GTK_IS_ENTRY_COMPLETION (completion));
1367   g_return_if_fail (column >= 0);
1368
1369   completion->priv->text_column = column;
1370
1371   cell = gtk_cell_renderer_text_new ();
1372   gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (completion),
1373                               cell, TRUE);
1374   gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (completion),
1375                                  cell,
1376                                  "text", column);
1377
1378   g_object_notify (G_OBJECT (completion), "text-column");
1379 }
1380
1381 /**
1382  * gtk_entry_completion_get_text_column:
1383  * @completion: a #GtkEntryCompletion
1384  *
1385  * Returns the column in the model of @completion to get strings from.
1386  *
1387  * Return value: the column containing the strings
1388  *
1389  * Since: 2.6
1390  */
1391 gint
1392 gtk_entry_completion_get_text_column (GtkEntryCompletion *completion)
1393 {
1394   g_return_val_if_fail (GTK_IS_ENTRY_COMPLETION (completion), -1);
1395
1396   return completion->priv->text_column;
1397 }
1398
1399 /* private */
1400
1401 static gboolean
1402 gtk_entry_completion_list_enter_notify (GtkWidget        *widget,
1403                                         GdkEventCrossing *event,
1404                                         gpointer          data)
1405 {
1406   GtkEntryCompletion *completion = GTK_ENTRY_COMPLETION (data);
1407
1408   return completion->priv->ignore_enter;
1409 }
1410
1411 static gboolean
1412 gtk_entry_completion_list_motion_notify (GtkWidget      *widget,
1413                                          GdkEventMotion *event,
1414                                          gpointer        data)
1415 {
1416   GtkEntryCompletion *completion = GTK_ENTRY_COMPLETION (data);
1417
1418   completion->priv->ignore_enter = FALSE;
1419
1420   return FALSE;
1421 }
1422
1423
1424 /* some nasty size requisition */
1425 gboolean
1426 _gtk_entry_completion_resize_popup (GtkEntryCompletion *completion)
1427 {
1428   GtkAllocation allocation;
1429   gint x, y;
1430   gint matches, actions, items, height, x_border, y_border;
1431   GdkScreen *screen;
1432   gint monitor_num;
1433   gint vertical_separator;
1434   GdkRectangle monitor;
1435   GdkWindow *window;
1436   GtkRequisition popup_req;
1437   GtkRequisition entry_req;
1438   GtkTreePath *path;
1439   gboolean above;
1440   gint width;
1441   GtkTreeViewColumn *action_column;
1442   gint action_height;
1443
1444   window = gtk_widget_get_window (completion->priv->entry);
1445
1446   if (!window)
1447     return FALSE;
1448
1449   gtk_widget_get_allocation (completion->priv->entry, &allocation);
1450   gtk_widget_get_preferred_size (completion->priv->entry,
1451                                  &entry_req, NULL);
1452
1453   gdk_window_get_origin (window, &x, &y);
1454   x += allocation.x;
1455   y += allocation.y + (allocation.height - entry_req.height) / 2;
1456
1457   _gtk_entry_get_borders (GTK_ENTRY (completion->priv->entry), &x_border, &y_border);
1458
1459   matches = gtk_tree_model_iter_n_children (GTK_TREE_MODEL (completion->priv->filter_model), NULL);
1460   actions = gtk_tree_model_iter_n_children (GTK_TREE_MODEL (completion->priv->actions), NULL);
1461   action_column  = gtk_tree_view_get_column (GTK_TREE_VIEW (completion->priv->action_view), 0);
1462
1463   gtk_tree_view_column_cell_get_size (completion->priv->column, NULL,
1464                                       NULL, NULL, NULL, &height);
1465   gtk_tree_view_column_cell_get_size (action_column, NULL,
1466                                       NULL, NULL, NULL, &action_height);
1467
1468   gtk_widget_style_get (GTK_WIDGET (completion->priv->tree_view),
1469                         "vertical-separator", &vertical_separator,
1470                         NULL);
1471
1472   height += vertical_separator;
1473
1474   gtk_widget_realize (completion->priv->tree_view);
1475
1476   screen = gtk_widget_get_screen (GTK_WIDGET (completion->priv->entry));
1477   monitor_num = gdk_screen_get_monitor_at_window (screen, window);
1478   gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor);
1479
1480
1481
1482   if (y > monitor.height / 2)
1483     items = MIN (matches, (((monitor.y + y) - (actions * action_height)) / height) - 1);
1484   else
1485     items = MIN (matches, (((monitor.height - y) - (actions * action_height)) / height) - 1);
1486
1487   if (items <= 0)
1488     gtk_widget_hide (completion->priv->scrolled_window);
1489   else
1490     gtk_widget_show (completion->priv->scrolled_window);
1491
1492   if (completion->priv->popup_set_width)
1493     width = MIN (allocation.width, monitor.width) - 2 * x_border;
1494   else
1495     width = -1;
1496
1497   gtk_tree_view_columns_autosize (GTK_TREE_VIEW (completion->priv->tree_view));
1498   gtk_scrolled_window_set_min_content_width (GTK_SCROLLED_WINDOW (completion->priv->scrolled_window), width);
1499   gtk_widget_set_size_request (completion->priv->scrolled_window, width, -1);
1500   gtk_scrolled_window_set_min_content_height (GTK_SCROLLED_WINDOW (completion->priv->scrolled_window), items * height);
1501
1502   if (actions)
1503     {
1504       gtk_widget_show (completion->priv->action_view);
1505       gtk_widget_set_size_request (completion->priv->action_view, width, -1);
1506     }
1507   else
1508     gtk_widget_hide (completion->priv->action_view);
1509
1510   gtk_widget_get_preferred_size (completion->priv->popup_window,
1511                                  &popup_req, NULL);
1512
1513   if (x < monitor.x)
1514     x = monitor.x;
1515   else if (x + popup_req.width > monitor.x + monitor.width)
1516     x = monitor.x + monitor.width - popup_req.width;
1517
1518   if (y + entry_req.height + popup_req.height <= monitor.y + monitor.height ||
1519       y - monitor.y < (monitor.y + monitor.height) - (y + entry_req.height))
1520     {
1521       y += entry_req.height;
1522       above = FALSE;
1523     }
1524   else
1525     {
1526       y -= popup_req.height;
1527       above = TRUE;
1528     }
1529
1530   if (matches > 0)
1531     {
1532       path = gtk_tree_path_new_from_indices (above ? matches - 1 : 0, -1);
1533       gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (completion->priv->tree_view), path,
1534                                     NULL, FALSE, 0.0, 0.0);
1535       gtk_tree_path_free (path);
1536     }
1537
1538   gtk_window_move (GTK_WINDOW (completion->priv->popup_window), x, y);
1539
1540   return above;
1541 }
1542
1543 void
1544 _gtk_entry_completion_popup (GtkEntryCompletion *completion,
1545                              GdkDevice          *device)
1546 {
1547   GtkTreeViewColumn *column;
1548   GtkStyleContext *context;
1549   GdkRGBA color;
1550   GList *renderers;
1551   GtkWidget *toplevel;
1552
1553   if (gtk_widget_get_mapped (completion->priv->popup_window))
1554     return;
1555
1556   if (!gtk_widget_get_mapped (completion->priv->entry))
1557     return;
1558
1559   if (!gtk_widget_has_focus (completion->priv->entry))
1560     return;
1561
1562   if (completion->priv->grab_device)
1563     return;
1564
1565   completion->priv->ignore_enter = TRUE;
1566
1567   column = gtk_tree_view_get_column (GTK_TREE_VIEW (completion->priv->action_view), 0);
1568   renderers = gtk_cell_layout_get_cells (GTK_CELL_LAYOUT (column));
1569
1570   context = gtk_widget_get_style_context (completion->priv->tree_view);
1571   gtk_style_context_get_background_color (context, 0, &color);
1572
1573   g_object_set (GTK_CELL_RENDERER (renderers->data),
1574                 "cell-background-rgba", &color,
1575                 NULL);
1576   g_list_free (renderers);
1577
1578   gtk_widget_show_all (completion->priv->vbox);
1579
1580   /* default on no match */
1581   completion->priv->current_selected = -1;
1582
1583   _gtk_entry_completion_resize_popup (completion);
1584
1585   toplevel = gtk_widget_get_toplevel (completion->priv->entry);
1586   if (GTK_IS_WINDOW (toplevel))
1587     gtk_window_group_add_window (gtk_window_get_group (GTK_WINDOW (toplevel)),
1588                                  GTK_WINDOW (completion->priv->popup_window));
1589
1590   /* prevent the first row being focused */
1591   gtk_widget_grab_focus (completion->priv->tree_view);
1592
1593   gtk_tree_selection_unselect_all (gtk_tree_view_get_selection (GTK_TREE_VIEW (completion->priv->tree_view)));
1594   gtk_tree_selection_unselect_all (gtk_tree_view_get_selection (GTK_TREE_VIEW (completion->priv->action_view)));
1595
1596   gtk_window_set_screen (GTK_WINDOW (completion->priv->popup_window),
1597                          gtk_widget_get_screen (completion->priv->entry));
1598
1599   gtk_widget_show (completion->priv->popup_window);
1600
1601   gtk_device_grab_add (completion->priv->popup_window, device, TRUE);
1602   gdk_device_grab (device, gtk_widget_get_window (completion->priv->popup_window),
1603                    GDK_OWNERSHIP_WINDOW, TRUE,
1604                    GDK_BUTTON_PRESS_MASK |
1605                    GDK_BUTTON_RELEASE_MASK |
1606                    GDK_POINTER_MOTION_MASK,
1607                    NULL, GDK_CURRENT_TIME);
1608
1609   completion->priv->grab_device = device;
1610 }
1611
1612 void
1613 _gtk_entry_completion_popdown (GtkEntryCompletion *completion)
1614 {
1615   if (!gtk_widget_get_mapped (completion->priv->popup_window))
1616     return;
1617
1618   completion->priv->ignore_enter = FALSE;
1619
1620   if (completion->priv->grab_device)
1621     {
1622       gdk_device_ungrab (completion->priv->grab_device, GDK_CURRENT_TIME);
1623       gtk_device_grab_remove (completion->priv->popup_window,
1624                               completion->priv->grab_device);
1625       completion->priv->grab_device = NULL;
1626     }
1627
1628   gtk_widget_hide (completion->priv->popup_window);
1629 }
1630
1631 static gboolean
1632 gtk_entry_completion_match_selected (GtkEntryCompletion *completion,
1633                                      GtkTreeModel       *model,
1634                                      GtkTreeIter        *iter)
1635 {
1636   gchar *str = NULL;
1637
1638   gtk_tree_model_get (model, iter, completion->priv->text_column, &str, -1);
1639   gtk_entry_set_text (GTK_ENTRY (completion->priv->entry), str ? str : "");
1640
1641   /* move cursor to the end */
1642   gtk_editable_set_position (GTK_EDITABLE (completion->priv->entry), -1);
1643
1644   g_free (str);
1645
1646   return TRUE;
1647 }
1648
1649 static gboolean
1650 gtk_entry_completion_cursor_on_match (GtkEntryCompletion *completion,
1651                                       GtkTreeModel       *model,
1652                                       GtkTreeIter        *iter)
1653 {
1654   gtk_entry_completion_insert_completion (completion, model, iter);
1655
1656   return TRUE;
1657 }
1658
1659 static gchar *
1660 gtk_entry_completion_compute_prefix (GtkEntryCompletion *completion)
1661 {
1662   GtkTreeIter iter;
1663   gchar *prefix = NULL;
1664   gboolean valid;
1665   const gchar *key;
1666
1667   if (completion->priv->text_column < 0)
1668     return NULL;
1669
1670   key = gtk_entry_get_text (GTK_ENTRY (completion->priv->entry));
1671
1672   valid = gtk_tree_model_get_iter_first (GTK_TREE_MODEL (completion->priv->filter_model),
1673                                          &iter);
1674
1675   while (valid)
1676     {
1677       gchar *text;
1678
1679       gtk_tree_model_get (GTK_TREE_MODEL (completion->priv->filter_model),
1680                           &iter, completion->priv->text_column, &text,
1681                           -1);
1682
1683       if (text && g_str_has_prefix (text, key))
1684         {
1685           if (!prefix)
1686             prefix = g_strdup (text);
1687           else
1688             {
1689               gchar *p = prefix;
1690               gchar *q = text;
1691
1692               while (*p && *p == *q)
1693                 {
1694                   p++;
1695                   q++;
1696                 }
1697
1698               *p = '\0';
1699
1700               if (p > prefix)
1701                 {
1702                   /* strip a partial multibyte character */
1703                   q = g_utf8_find_prev_char (prefix, p);
1704                   switch (g_utf8_get_char_validated (q, p - q))
1705                     {
1706                     case (gunichar)-2:
1707                     case (gunichar)-1:
1708                       *q = 0;
1709                     default: ;
1710                     }
1711                 }
1712             }
1713         }
1714
1715       g_free (text);
1716       valid = gtk_tree_model_iter_next (GTK_TREE_MODEL (completion->priv->filter_model),
1717                                         &iter);
1718     }
1719
1720   return prefix;
1721 }
1722
1723
1724 static gboolean
1725 gtk_entry_completion_real_insert_prefix (GtkEntryCompletion *completion,
1726                                          const gchar        *prefix)
1727 {
1728   if (prefix)
1729     {
1730       gint key_len;
1731       gint prefix_len;
1732       const gchar *key;
1733
1734       prefix_len = g_utf8_strlen (prefix, -1);
1735
1736       key = gtk_entry_get_text (GTK_ENTRY (completion->priv->entry));
1737       key_len = g_utf8_strlen (key, -1);
1738
1739       if (prefix_len > key_len)
1740         {
1741           gint pos = prefix_len;
1742
1743           gtk_editable_insert_text (GTK_EDITABLE (completion->priv->entry),
1744                                     prefix + strlen (key), -1, &pos);
1745           gtk_editable_select_region (GTK_EDITABLE (completion->priv->entry),
1746                                       key_len, prefix_len);
1747
1748           completion->priv->has_completion = TRUE;
1749         }
1750     }
1751
1752   return TRUE;
1753 }
1754
1755 /**
1756  * gtk_entry_completion_get_completion_prefix:
1757  * @completion: a #GtkEntryCompletion
1758  *
1759  * Get the original text entered by the user that triggered
1760  * the completion or %NULL if there's no completion ongoing.
1761  *
1762  * Returns: the prefix for the current completion
1763  *
1764  * Since: 2.12
1765  */
1766 const gchar*
1767 gtk_entry_completion_get_completion_prefix (GtkEntryCompletion *completion)
1768 {
1769   g_return_val_if_fail (GTK_IS_ENTRY_COMPLETION (completion), NULL);
1770
1771   return completion->priv->completion_prefix;
1772 }
1773
1774 static void
1775 gtk_entry_completion_insert_completion_text (GtkEntryCompletion *completion,
1776                                              const gchar *text)
1777 {
1778   GtkEntryCompletionPrivate *priv = completion->priv;
1779   gint len;
1780
1781   priv = completion->priv;
1782
1783   if (priv->changed_id > 0)
1784     g_signal_handler_block (priv->entry, priv->changed_id);
1785
1786   if (priv->insert_text_id > 0)
1787     g_signal_handler_block (priv->entry, priv->insert_text_id);
1788
1789   gtk_entry_set_text (GTK_ENTRY (priv->entry), text);
1790
1791   len = strlen (priv->completion_prefix);
1792   gtk_editable_select_region (GTK_EDITABLE (priv->entry), len, -1);
1793
1794   if (priv->changed_id > 0)
1795     g_signal_handler_unblock (priv->entry, priv->changed_id);
1796
1797   if (priv->insert_text_id > 0)
1798     g_signal_handler_unblock (priv->entry, priv->insert_text_id);
1799 }
1800
1801 static gboolean
1802 gtk_entry_completion_insert_completion (GtkEntryCompletion *completion,
1803                                         GtkTreeModel       *model,
1804                                         GtkTreeIter        *iter)
1805 {
1806   gchar *str = NULL;
1807
1808   if (completion->priv->text_column < 0)
1809     return FALSE;
1810
1811   gtk_tree_model_get (model, iter,
1812                       completion->priv->text_column, &str,
1813                       -1);
1814
1815   gtk_entry_completion_insert_completion_text (completion, str);
1816
1817   g_free (str);
1818
1819   return TRUE;
1820 }
1821
1822 /**
1823  * gtk_entry_completion_insert_prefix:
1824  * @completion: a #GtkEntryCompletion
1825  *
1826  * Requests a prefix insertion.
1827  *
1828  * Since: 2.6
1829  */
1830 void
1831 gtk_entry_completion_insert_prefix (GtkEntryCompletion *completion)
1832 {
1833   gboolean done;
1834   gchar *prefix;
1835
1836   if (completion->priv->insert_text_id > 0)
1837     g_signal_handler_block (completion->priv->entry,
1838                             completion->priv->insert_text_id);
1839
1840   prefix = gtk_entry_completion_compute_prefix (completion);
1841   if (prefix)
1842     {
1843       g_signal_emit (completion, entry_completion_signals[INSERT_PREFIX],
1844                      0, prefix, &done);
1845       g_free (prefix);
1846     }
1847
1848   if (completion->priv->insert_text_id > 0)
1849     g_signal_handler_unblock (completion->priv->entry,
1850                               completion->priv->insert_text_id);
1851 }
1852
1853 /**
1854  * gtk_entry_completion_set_inline_completion:
1855  * @completion: a #GtkEntryCompletion
1856  * @inline_completion: %TRUE to do inline completion
1857  *
1858  * Sets whether the common prefix of the possible completions should
1859  * be automatically inserted in the entry.
1860  *
1861  * Since: 2.6
1862  */
1863 void
1864 gtk_entry_completion_set_inline_completion (GtkEntryCompletion *completion,
1865                                             gboolean            inline_completion)
1866 {
1867   g_return_if_fail (GTK_IS_ENTRY_COMPLETION (completion));
1868
1869   inline_completion = inline_completion != FALSE;
1870
1871   if (completion->priv->inline_completion != inline_completion)
1872     {
1873       completion->priv->inline_completion = inline_completion;
1874
1875       g_object_notify (G_OBJECT (completion), "inline-completion");
1876     }
1877 }
1878
1879 /**
1880  * gtk_entry_completion_get_inline_completion:
1881  * @completion: a #GtkEntryCompletion
1882  *
1883  * Returns whether the common prefix of the possible completions should
1884  * be automatically inserted in the entry.
1885  *
1886  * Return value: %TRUE if inline completion is turned on
1887  *
1888  * Since: 2.6
1889  */
1890 gboolean
1891 gtk_entry_completion_get_inline_completion (GtkEntryCompletion *completion)
1892 {
1893   g_return_val_if_fail (GTK_IS_ENTRY_COMPLETION (completion), FALSE);
1894
1895   return completion->priv->inline_completion;
1896 }
1897
1898 /**
1899  * gtk_entry_completion_set_popup_completion:
1900  * @completion: a #GtkEntryCompletion
1901  * @popup_completion: %TRUE to do popup completion
1902  *
1903  * Sets whether the completions should be presented in a popup window.
1904  *
1905  * Since: 2.6
1906  */
1907 void
1908 gtk_entry_completion_set_popup_completion (GtkEntryCompletion *completion,
1909                                            gboolean            popup_completion)
1910 {
1911   g_return_if_fail (GTK_IS_ENTRY_COMPLETION (completion));
1912
1913   popup_completion = popup_completion != FALSE;
1914
1915   if (completion->priv->popup_completion != popup_completion)
1916     {
1917       completion->priv->popup_completion = popup_completion;
1918
1919       g_object_notify (G_OBJECT (completion), "popup-completion");
1920     }
1921 }
1922
1923
1924 /**
1925  * gtk_entry_completion_get_popup_completion:
1926  * @completion: a #GtkEntryCompletion
1927  *
1928  * Returns whether the completions should be presented in a popup window.
1929  *
1930  * Return value: %TRUE if popup completion is turned on
1931  *
1932  * Since: 2.6
1933  */
1934 gboolean
1935 gtk_entry_completion_get_popup_completion (GtkEntryCompletion *completion)
1936 {
1937   g_return_val_if_fail (GTK_IS_ENTRY_COMPLETION (completion), TRUE);
1938
1939   return completion->priv->popup_completion;
1940 }
1941
1942 /**
1943  * gtk_entry_completion_set_popup_set_width:
1944  * @completion: a #GtkEntryCompletion
1945  * @popup_set_width: %TRUE to make the width of the popup the same as the entry
1946  *
1947  * Sets whether the completion popup window will be resized to be the same
1948  * width as the entry.
1949  *
1950  * Since: 2.8
1951  */
1952 void
1953 gtk_entry_completion_set_popup_set_width (GtkEntryCompletion *completion,
1954                                           gboolean            popup_set_width)
1955 {
1956   g_return_if_fail (GTK_IS_ENTRY_COMPLETION (completion));
1957
1958   popup_set_width = popup_set_width != FALSE;
1959
1960   if (completion->priv->popup_set_width != popup_set_width)
1961     {
1962       completion->priv->popup_set_width = popup_set_width;
1963
1964       g_object_notify (G_OBJECT (completion), "popup-set-width");
1965     }
1966 }
1967
1968 /**
1969  * gtk_entry_completion_get_popup_set_width:
1970  * @completion: a #GtkEntryCompletion
1971  *
1972  * Returns whether the  completion popup window will be resized to the
1973  * width of the entry.
1974  *
1975  * Return value: %TRUE if the popup window will be resized to the width of
1976  *   the entry
1977  *
1978  * Since: 2.8
1979  */
1980 gboolean
1981 gtk_entry_completion_get_popup_set_width (GtkEntryCompletion *completion)
1982 {
1983   g_return_val_if_fail (GTK_IS_ENTRY_COMPLETION (completion), TRUE);
1984
1985   return completion->priv->popup_set_width;
1986 }
1987
1988
1989 /**
1990  * gtk_entry_completion_set_popup_single_match:
1991  * @completion: a #GtkEntryCompletion
1992  * @popup_single_match: %TRUE if the popup should appear even for a single
1993  *     match
1994  *
1995  * Sets whether the completion popup window will appear even if there is
1996  * only a single match. You may want to set this to %FALSE if you
1997  * are using <link linkend="GtkEntryCompletion--inline-completion">inline
1998  * completion</link>.
1999  *
2000  * Since: 2.8
2001  */
2002 void
2003 gtk_entry_completion_set_popup_single_match (GtkEntryCompletion *completion,
2004                                              gboolean            popup_single_match)
2005 {
2006   g_return_if_fail (GTK_IS_ENTRY_COMPLETION (completion));
2007
2008   popup_single_match = popup_single_match != FALSE;
2009
2010   if (completion->priv->popup_single_match != popup_single_match)
2011     {
2012       completion->priv->popup_single_match = popup_single_match;
2013
2014       g_object_notify (G_OBJECT (completion), "popup-single-match");
2015     }
2016 }
2017
2018 /**
2019  * gtk_entry_completion_get_popup_single_match:
2020  * @completion: a #GtkEntryCompletion
2021  *
2022  * Returns whether the completion popup window will appear even if there is
2023  * only a single match.
2024  *
2025  * Return value: %TRUE if the popup window will appear regardless of the
2026  *    number of matches
2027  *
2028  * Since: 2.8
2029  */
2030 gboolean
2031 gtk_entry_completion_get_popup_single_match (GtkEntryCompletion *completion)
2032 {
2033   g_return_val_if_fail (GTK_IS_ENTRY_COMPLETION (completion), TRUE);
2034
2035   return completion->priv->popup_single_match;
2036 }
2037
2038 /**
2039  * gtk_entry_completion_set_inline_selection:
2040  * @completion: a #GtkEntryCompletion
2041  * @inline_selection: %TRUE to do inline selection
2042  *
2043  * Sets whether it is possible to cycle through the possible completions
2044  * inside the entry.
2045  *
2046  * Since: 2.12
2047  */
2048 void
2049 gtk_entry_completion_set_inline_selection (GtkEntryCompletion *completion,
2050                                            gboolean inline_selection)
2051 {
2052   g_return_if_fail (GTK_IS_ENTRY_COMPLETION (completion));
2053
2054   inline_selection = inline_selection != FALSE;
2055
2056   if (completion->priv->inline_selection != inline_selection)
2057     {
2058       completion->priv->inline_selection = inline_selection;
2059
2060       g_object_notify (G_OBJECT (completion), "inline-selection");
2061     }
2062 }
2063
2064 /**
2065  * gtk_entry_completion_get_inline_selection:
2066  * @completion: a #GtkEntryCompletion
2067  *
2068  * Returns %TRUE if inline-selection mode is turned on.
2069  *
2070  * Returns: %TRUE if inline-selection mode is on
2071  *
2072  * Since: 2.12
2073  */
2074 gboolean
2075 gtk_entry_completion_get_inline_selection (GtkEntryCompletion *completion)
2076 {
2077   g_return_val_if_fail (GTK_IS_ENTRY_COMPLETION (completion), FALSE);
2078
2079   return completion->priv->inline_selection;
2080 }