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