]> Pileus Git - ~andy/gtk/blob - gtk/gtkentrycompletion.c
notebook: restore previous behaviour wrt. unparenting of tab labels
[~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         gtk_entry_completion_set_text_column (completion,
655                                               g_value_get_int (value));
656         break;
657
658       case PROP_INLINE_COMPLETION:
659         gtk_entry_completion_set_inline_completion (completion,
660                                                     g_value_get_boolean (value));
661         break;
662
663       case PROP_POPUP_COMPLETION:
664         gtk_entry_completion_set_popup_completion (completion,
665                                                    g_value_get_boolean (value));
666         break;
667
668       case PROP_POPUP_SET_WIDTH:
669         gtk_entry_completion_set_popup_set_width (completion,
670                                                   g_value_get_boolean (value));
671         break;
672
673       case PROP_POPUP_SINGLE_MATCH:
674         gtk_entry_completion_set_popup_single_match (completion,
675                                                      g_value_get_boolean (value));
676         break;
677
678       case PROP_INLINE_SELECTION:
679         gtk_entry_completion_set_inline_selection (completion,
680                                                    g_value_get_boolean (value));
681         break;
682
683       case PROP_CELL_AREA:
684         /* Construct-only, can only be assigned once */
685         area = g_value_get_object (value);
686         if (area)
687           {
688             if (priv->cell_area != NULL)
689               {
690                 g_warning ("cell-area has already been set, ignoring construct property");
691                 g_object_ref_sink (area);
692                 g_object_unref (area);
693               }
694             else
695               priv->cell_area = g_object_ref_sink (area);
696           }
697         break;
698
699       default:
700         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
701         break;
702     }
703 }
704
705 static void
706 gtk_entry_completion_get_property (GObject    *object,
707                                    guint       prop_id,
708                                    GValue     *value,
709                                    GParamSpec *pspec)
710 {
711   GtkEntryCompletion *completion = GTK_ENTRY_COMPLETION (object);
712
713   switch (prop_id)
714     {
715       case PROP_MODEL:
716         g_value_set_object (value,
717                             gtk_entry_completion_get_model (completion));
718         break;
719
720       case PROP_MINIMUM_KEY_LENGTH:
721         g_value_set_int (value, gtk_entry_completion_get_minimum_key_length (completion));
722         break;
723
724       case PROP_TEXT_COLUMN:
725         g_value_set_int (value, gtk_entry_completion_get_text_column (completion));
726         break;
727
728       case PROP_INLINE_COMPLETION:
729         g_value_set_boolean (value, gtk_entry_completion_get_inline_completion (completion));
730         break;
731
732       case PROP_POPUP_COMPLETION:
733         g_value_set_boolean (value, gtk_entry_completion_get_popup_completion (completion));
734         break;
735
736       case PROP_POPUP_SET_WIDTH:
737         g_value_set_boolean (value, gtk_entry_completion_get_popup_set_width (completion));
738         break;
739
740       case PROP_POPUP_SINGLE_MATCH:
741         g_value_set_boolean (value, gtk_entry_completion_get_popup_single_match (completion));
742         break;
743
744       case PROP_INLINE_SELECTION:
745         g_value_set_boolean (value, gtk_entry_completion_get_inline_selection (completion));
746         break;
747
748       case PROP_CELL_AREA:
749         g_value_set_object (value, completion->priv->cell_area);
750         break;
751
752       default:
753         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
754         break;
755     }
756 }
757
758 static void
759 gtk_entry_completion_finalize (GObject *object)
760 {
761   GtkEntryCompletion *completion = GTK_ENTRY_COMPLETION (object);
762   GtkEntryCompletionPrivate *priv = completion->priv;
763
764   g_free (priv->case_normalized_key);
765   g_free (priv->completion_prefix);
766
767   if (priv->match_notify)
768     (* priv->match_notify) (priv->match_data);
769
770   G_OBJECT_CLASS (gtk_entry_completion_parent_class)->finalize (object);
771 }
772
773 static void
774 gtk_entry_completion_dispose (GObject *object)
775 {
776   GtkEntryCompletion *completion = GTK_ENTRY_COMPLETION (object);
777   GtkEntryCompletionPrivate *priv = completion->priv;
778
779   if (priv->tree_view)
780     {
781       gtk_widget_destroy (priv->tree_view);
782       priv->tree_view = NULL;
783     }
784
785   if (priv->entry)
786     gtk_entry_set_completion (GTK_ENTRY (priv->entry), NULL);
787
788   if (priv->actions)
789     {
790       g_object_unref (priv->actions);
791       priv->actions = NULL;
792     }
793
794   if (priv->action_view)
795     {
796       g_object_unref (priv->action_view);
797       priv->action_view = NULL;
798     }
799
800   if (priv->popup_window)
801     {
802       gtk_widget_destroy (priv->popup_window);
803       priv->popup_window = NULL;
804     }
805
806   if (priv->cell_area)
807     {
808       g_object_unref (priv->cell_area);
809       priv->cell_area = NULL;
810     }
811
812   G_OBJECT_CLASS (gtk_entry_completion_parent_class)->dispose (object);
813 }
814
815 /* implement cell layout interface (only need to return the underlying cell area) */
816 static GtkCellArea*
817 gtk_entry_completion_get_area (GtkCellLayout *cell_layout)
818 {
819   GtkEntryCompletionPrivate *priv;
820
821   priv = GTK_ENTRY_COMPLETION (cell_layout)->priv;
822
823   if (G_UNLIKELY (!priv->cell_area))
824     {
825       priv->cell_area = gtk_cell_area_box_new ();
826       g_object_ref_sink (priv->cell_area);
827     }
828
829   return priv->cell_area;
830 }
831
832 /* all those callbacks */
833 static gboolean
834 gtk_entry_completion_default_completion_func (GtkEntryCompletion *completion,
835                                               const gchar        *key,
836                                               GtkTreeIter        *iter,
837                                               gpointer            user_data)
838 {
839   gchar *item = NULL;
840   gchar *normalized_string;
841   gchar *case_normalized_string;
842
843   gboolean ret = FALSE;
844
845   GtkTreeModel *model;
846
847   model = gtk_tree_model_filter_get_model (completion->priv->filter_model);
848
849   g_return_val_if_fail (gtk_tree_model_get_column_type (model, completion->priv->text_column) == G_TYPE_STRING,
850                         FALSE);
851
852   gtk_tree_model_get (model, iter,
853                       completion->priv->text_column, &item,
854                       -1);
855
856   if (item != NULL)
857     {
858       normalized_string = g_utf8_normalize (item, -1, G_NORMALIZE_ALL);
859
860       if (normalized_string != NULL)
861         {
862           case_normalized_string = g_utf8_casefold (normalized_string, -1);
863
864           if (!strncmp (key, case_normalized_string, strlen (key)))
865             ret = TRUE;
866
867           g_free (case_normalized_string);
868         }
869       g_free (normalized_string);
870     }
871   g_free (item);
872
873   return ret;
874 }
875
876 static gboolean
877 gtk_entry_completion_visible_func (GtkTreeModel *model,
878                                    GtkTreeIter  *iter,
879                                    gpointer      data)
880 {
881   gboolean ret = FALSE;
882
883   GtkEntryCompletion *completion = GTK_ENTRY_COMPLETION (data);
884
885   if (!completion->priv->case_normalized_key)
886     return ret;
887
888   if (completion->priv->match_func)
889     ret = (* completion->priv->match_func) (completion,
890                                             completion->priv->case_normalized_key,
891                                             iter,
892                                             completion->priv->match_data);
893   else if (completion->priv->text_column >= 0)
894     ret = gtk_entry_completion_default_completion_func (completion,
895                                                         completion->priv->case_normalized_key,
896                                                         iter,
897                                                         NULL);
898
899   return ret;
900 }
901
902 static gboolean
903 gtk_entry_completion_popup_key_event (GtkWidget   *widget,
904                                       GdkEventKey *event,
905                                       gpointer     user_data)
906 {
907   GtkEntryCompletion *completion = GTK_ENTRY_COMPLETION (user_data);
908
909   if (!gtk_widget_get_mapped (completion->priv->popup_window))
910     return FALSE;
911
912   /* propagate event to the entry */
913   gtk_widget_event (completion->priv->entry, (GdkEvent *)event);
914
915   return TRUE;
916 }
917
918 static gboolean
919 gtk_entry_completion_popup_button_press (GtkWidget      *widget,
920                                          GdkEventButton *event,
921                                          gpointer        user_data)
922 {
923   GtkEntryCompletion *completion = GTK_ENTRY_COMPLETION (user_data);
924
925   if (!gtk_widget_get_mapped (completion->priv->popup_window))
926     return FALSE;
927
928   /* if we come here, it's usually time to popdown */
929   _gtk_entry_completion_popdown (completion);
930
931   return TRUE;
932 }
933
934 static gboolean
935 gtk_entry_completion_list_button_press (GtkWidget      *widget,
936                                         GdkEventButton *event,
937                                         gpointer        user_data)
938 {
939   GtkEntryCompletion *completion = GTK_ENTRY_COMPLETION (user_data);
940   GtkTreePath *path = NULL;
941
942   if (!gtk_widget_get_mapped (completion->priv->popup_window))
943     return FALSE;
944
945   if (gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (widget),
946                                      event->x, event->y,
947                                      &path, NULL, NULL, NULL))
948     {
949       GtkTreeIter iter;
950       gboolean entry_set;
951       GtkTreeModel *model;
952       GtkTreeIter child_iter;
953
954       gtk_tree_model_get_iter (GTK_TREE_MODEL (completion->priv->filter_model),
955                                &iter, path);
956       gtk_tree_path_free (path);
957       gtk_tree_model_filter_convert_iter_to_child_iter (completion->priv->filter_model,
958                                                         &child_iter,
959                                                         &iter);
960       model = gtk_tree_model_filter_get_model (completion->priv->filter_model);
961
962       g_signal_handler_block (completion->priv->entry,
963                               completion->priv->changed_id);
964       g_signal_emit (completion, entry_completion_signals[MATCH_SELECTED],
965                      0, model, &child_iter, &entry_set);
966       g_signal_handler_unblock (completion->priv->entry,
967                                 completion->priv->changed_id);
968
969       _gtk_entry_completion_popdown (completion);
970
971       return TRUE;
972     }
973
974   return FALSE;
975 }
976
977 static gboolean
978 gtk_entry_completion_action_button_press (GtkWidget      *widget,
979                                           GdkEventButton *event,
980                                           gpointer        user_data)
981 {
982   GtkEntryCompletion *completion = GTK_ENTRY_COMPLETION (user_data);
983   GtkTreePath *path = NULL;
984
985   if (!gtk_widget_get_mapped (completion->priv->popup_window))
986     return FALSE;
987
988   _gtk_entry_reset_im_context (GTK_ENTRY (completion->priv->entry));
989
990   if (gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (widget),
991                                      event->x, event->y,
992                                      &path, NULL, NULL, NULL))
993     {
994       g_signal_emit (completion, entry_completion_signals[ACTION_ACTIVATED],
995                      0, gtk_tree_path_get_indices (path)[0]);
996       gtk_tree_path_free (path);
997
998       _gtk_entry_completion_popdown (completion);
999       return TRUE;
1000     }
1001
1002   return FALSE;
1003 }
1004
1005 static void
1006 gtk_entry_completion_action_data_func (GtkTreeViewColumn *tree_column,
1007                                        GtkCellRenderer   *cell,
1008                                        GtkTreeModel      *model,
1009                                        GtkTreeIter       *iter,
1010                                        gpointer           data)
1011 {
1012   gchar *string = NULL;
1013   gboolean markup;
1014
1015   gtk_tree_model_get (model, iter,
1016                       0, &string,
1017                       1, &markup,
1018                       -1);
1019
1020   if (!string)
1021     return;
1022
1023   if (markup)
1024     g_object_set (cell,
1025                   "text", NULL,
1026                   "markup", string,
1027                   NULL);
1028   else
1029     g_object_set (cell,
1030                   "markup", NULL,
1031                   "text", string,
1032                   NULL);
1033
1034   g_free (string);
1035 }
1036
1037 static void
1038 gtk_entry_completion_selection_changed (GtkTreeSelection *selection,
1039                                         gpointer          data)
1040 {
1041   GtkEntryCompletion *completion = GTK_ENTRY_COMPLETION (data);
1042
1043   if (completion->priv->first_sel_changed)
1044     {
1045       completion->priv->first_sel_changed = FALSE;
1046       if (gtk_widget_is_focus (completion->priv->tree_view))
1047         gtk_tree_selection_unselect_all (selection);
1048     }
1049 }
1050
1051 /* public API */
1052
1053 /**
1054  * gtk_entry_completion_new:
1055  *
1056  * Creates a new #GtkEntryCompletion object.
1057  *
1058  * Return value: A newly created #GtkEntryCompletion object
1059  *
1060  * Since: 2.4
1061  */
1062 GtkEntryCompletion *
1063 gtk_entry_completion_new (void)
1064 {
1065   GtkEntryCompletion *completion;
1066
1067   completion = g_object_new (GTK_TYPE_ENTRY_COMPLETION, NULL);
1068
1069   return completion;
1070 }
1071
1072 /**
1073  * gtk_entry_completion_new_with_area:
1074  * @area: the #GtkCellArea used to layout cells
1075  *
1076  * Creates a new #GtkEntryCompletion object using the
1077  * specified @area to layout cells in the underlying
1078  * #GtkTreeViewColumn for the drop-down menu.
1079  *
1080  * Return value: A newly created #GtkEntryCompletion object
1081  *
1082  * Since: 3.0
1083  */
1084 GtkEntryCompletion *
1085 gtk_entry_completion_new_with_area (GtkCellArea *area)
1086 {
1087   GtkEntryCompletion *completion;
1088
1089   completion = g_object_new (GTK_TYPE_ENTRY_COMPLETION, "cell-area", area, NULL);
1090
1091   return completion;
1092 }
1093
1094 /**
1095  * gtk_entry_completion_get_entry:
1096  * @completion: a #GtkEntryCompletion
1097  *
1098  * Gets the entry @completion has been attached to.
1099  *
1100  * Return value: (transfer none): The entry @completion has been attached to
1101  *
1102  * Since: 2.4
1103  */
1104 GtkWidget *
1105 gtk_entry_completion_get_entry (GtkEntryCompletion *completion)
1106 {
1107   g_return_val_if_fail (GTK_IS_ENTRY_COMPLETION (completion), NULL);
1108
1109   return completion->priv->entry;
1110 }
1111
1112 /**
1113  * gtk_entry_completion_set_model:
1114  * @completion: a #GtkEntryCompletion
1115  * @model: (allow-none): the #GtkTreeModel
1116  *
1117  * Sets the model for a #GtkEntryCompletion. If @completion already has
1118  * a model set, it will remove it before setting the new model.
1119  * If model is %NULL, then it will unset the model.
1120  *
1121  * Since: 2.4
1122  */
1123 void
1124 gtk_entry_completion_set_model (GtkEntryCompletion *completion,
1125                                 GtkTreeModel       *model)
1126 {
1127   g_return_if_fail (GTK_IS_ENTRY_COMPLETION (completion));
1128   g_return_if_fail (model == NULL || GTK_IS_TREE_MODEL (model));
1129
1130   if (!model)
1131     {
1132       gtk_tree_view_set_model (GTK_TREE_VIEW (completion->priv->tree_view),
1133                                NULL);
1134       _gtk_entry_completion_popdown (completion);
1135       completion->priv->filter_model = NULL;
1136       return;
1137     }
1138
1139   /* code will unref the old filter model (if any) */
1140   completion->priv->filter_model =
1141     GTK_TREE_MODEL_FILTER (gtk_tree_model_filter_new (model, NULL));
1142   gtk_tree_model_filter_set_visible_func (completion->priv->filter_model,
1143                                           gtk_entry_completion_visible_func,
1144                                           completion,
1145                                           NULL);
1146
1147   gtk_tree_view_set_model (GTK_TREE_VIEW (completion->priv->tree_view),
1148                            GTK_TREE_MODEL (completion->priv->filter_model));
1149   g_object_unref (completion->priv->filter_model);
1150
1151   g_object_notify (G_OBJECT (completion), "model");
1152
1153   if (gtk_widget_get_visible (completion->priv->popup_window))
1154     _gtk_entry_completion_resize_popup (completion);
1155 }
1156
1157 /**
1158  * gtk_entry_completion_get_model:
1159  * @completion: a #GtkEntryCompletion
1160  *
1161  * Returns the model the #GtkEntryCompletion is using as data source.
1162  * Returns %NULL if the model is unset.
1163  *
1164  * Return value: (transfer none): A #GtkTreeModel, or %NULL if none
1165  *     is currently being used
1166  *
1167  * Since: 2.4
1168  */
1169 GtkTreeModel *
1170 gtk_entry_completion_get_model (GtkEntryCompletion *completion)
1171 {
1172   g_return_val_if_fail (GTK_IS_ENTRY_COMPLETION (completion), NULL);
1173
1174   if (!completion->priv->filter_model)
1175     return NULL;
1176
1177   return gtk_tree_model_filter_get_model (completion->priv->filter_model);
1178 }
1179
1180 /**
1181  * gtk_entry_completion_set_match_func:
1182  * @completion: a #GtkEntryCompletion
1183  * @func: the #GtkEntryCompletionMatchFunc to use
1184  * @func_data: user data for @func
1185  * @func_notify: destroy notify for @func_data.
1186  *
1187  * Sets the match function for @completion to be @func. The match function
1188  * is used to determine if a row should or should not be in the completion
1189  * list.
1190  *
1191  * Since: 2.4
1192  */
1193 void
1194 gtk_entry_completion_set_match_func (GtkEntryCompletion          *completion,
1195                                      GtkEntryCompletionMatchFunc  func,
1196                                      gpointer                     func_data,
1197                                      GDestroyNotify               func_notify)
1198 {
1199   g_return_if_fail (GTK_IS_ENTRY_COMPLETION (completion));
1200
1201   if (completion->priv->match_notify)
1202     (* completion->priv->match_notify) (completion->priv->match_data);
1203
1204   completion->priv->match_func = func;
1205   completion->priv->match_data = func_data;
1206   completion->priv->match_notify = func_notify;
1207 }
1208
1209 /**
1210  * gtk_entry_completion_set_minimum_key_length:
1211  * @completion: a #GtkEntryCompletion
1212  * @length: the minimum length of the key in order to start completing
1213  *
1214  * Requires the length of the search key for @completion to be at least
1215  * @length. This is useful for long lists, where completing using a small
1216  * key takes a lot of time and will come up with meaningless results anyway
1217  * (ie, a too large dataset).
1218  *
1219  * Since: 2.4
1220  */
1221 void
1222 gtk_entry_completion_set_minimum_key_length (GtkEntryCompletion *completion,
1223                                              gint                length)
1224 {
1225   g_return_if_fail (GTK_IS_ENTRY_COMPLETION (completion));
1226   g_return_if_fail (length >= 0);
1227
1228   if (completion->priv->minimum_key_length != length)
1229     {
1230       completion->priv->minimum_key_length = length;
1231
1232       g_object_notify (G_OBJECT (completion), "minimum-key-length");
1233     }
1234 }
1235
1236 /**
1237  * gtk_entry_completion_get_minimum_key_length:
1238  * @completion: a #GtkEntryCompletion
1239  *
1240  * Returns the minimum key length as set for @completion.
1241  *
1242  * Return value: The currently used minimum key length
1243  *
1244  * Since: 2.4
1245  */
1246 gint
1247 gtk_entry_completion_get_minimum_key_length (GtkEntryCompletion *completion)
1248 {
1249   g_return_val_if_fail (GTK_IS_ENTRY_COMPLETION (completion), 0);
1250
1251   return completion->priv->minimum_key_length;
1252 }
1253
1254 /**
1255  * gtk_entry_completion_complete:
1256  * @completion: a #GtkEntryCompletion
1257  *
1258  * Requests a completion operation, or in other words a refiltering of the
1259  * current list with completions, using the current key. The completion list
1260  * view will be updated accordingly.
1261  *
1262  * Since: 2.4
1263  */
1264 void
1265 gtk_entry_completion_complete (GtkEntryCompletion *completion)
1266 {
1267   gchar *tmp;
1268
1269   g_return_if_fail (GTK_IS_ENTRY_COMPLETION (completion));
1270   g_return_if_fail (GTK_IS_ENTRY (completion->priv->entry));
1271
1272   if (!completion->priv->filter_model)
1273     return;
1274
1275   g_free (completion->priv->case_normalized_key);
1276
1277   tmp = g_utf8_normalize (gtk_entry_get_text (GTK_ENTRY (completion->priv->entry)),
1278                           -1, G_NORMALIZE_ALL);
1279   completion->priv->case_normalized_key = g_utf8_casefold (tmp, -1);
1280   g_free (tmp);
1281
1282   gtk_tree_model_filter_refilter (completion->priv->filter_model);
1283
1284   if (gtk_widget_get_visible (completion->priv->popup_window))
1285     _gtk_entry_completion_resize_popup (completion);
1286 }
1287
1288 static void
1289 gtk_entry_completion_insert_action (GtkEntryCompletion *completion,
1290                                     gint                index,
1291                                     const gchar        *string,
1292                                     gboolean            markup)
1293 {
1294   GtkTreeIter iter;
1295
1296   gtk_list_store_insert (completion->priv->actions, &iter, index);
1297   gtk_list_store_set (completion->priv->actions, &iter,
1298                       0, string,
1299                       1, markup,
1300                       -1);
1301
1302   if (!gtk_widget_get_parent (completion->priv->action_view))
1303     {
1304       GtkTreePath *path = gtk_tree_path_new_from_indices (0, -1);
1305
1306       gtk_tree_view_set_cursor (GTK_TREE_VIEW (completion->priv->action_view),
1307                                 path, NULL, FALSE);
1308       gtk_tree_path_free (path);
1309
1310       gtk_box_pack_start (GTK_BOX (completion->priv->vbox),
1311                           completion->priv->action_view, FALSE, FALSE, 0);
1312       gtk_widget_show (completion->priv->action_view);
1313     }
1314 }
1315
1316 /**
1317  * gtk_entry_completion_insert_action_text:
1318  * @completion: a #GtkEntryCompletion
1319  * @index_: the index of the item to insert
1320  * @text: text of the item to insert
1321  *
1322  * Inserts an action in @completion's action item list at position @index_
1323  * with text @text. If you want the action item to have markup, use
1324  * gtk_entry_completion_insert_action_markup().
1325  *
1326  * Since: 2.4
1327  */
1328 void
1329 gtk_entry_completion_insert_action_text (GtkEntryCompletion *completion,
1330                                          gint                index_,
1331                                          const gchar        *text)
1332 {
1333   g_return_if_fail (GTK_IS_ENTRY_COMPLETION (completion));
1334   g_return_if_fail (text != NULL);
1335
1336   gtk_entry_completion_insert_action (completion, index_, text, FALSE);
1337 }
1338
1339 /**
1340  * gtk_entry_completion_insert_action_markup:
1341  * @completion: a #GtkEntryCompletion
1342  * @index_: the index of the item to insert
1343  * @markup: markup of the item to insert
1344  *
1345  * Inserts an action in @completion's action item list at position @index_
1346  * with markup @markup.
1347  *
1348  * Since: 2.4
1349  */
1350 void
1351 gtk_entry_completion_insert_action_markup (GtkEntryCompletion *completion,
1352                                            gint                index_,
1353                                            const gchar        *markup)
1354 {
1355   g_return_if_fail (GTK_IS_ENTRY_COMPLETION (completion));
1356   g_return_if_fail (markup != NULL);
1357
1358   gtk_entry_completion_insert_action (completion, index_, markup, TRUE);
1359 }
1360
1361 /**
1362  * gtk_entry_completion_delete_action:
1363  * @completion: a #GtkEntryCompletion
1364  * @index_: the index of the item to delete
1365  *
1366  * Deletes the action at @index_ from @completion's action list.
1367  *
1368  * Since: 2.4
1369  */
1370 void
1371 gtk_entry_completion_delete_action (GtkEntryCompletion *completion,
1372                                     gint                index_)
1373 {
1374   GtkTreeIter iter;
1375
1376   g_return_if_fail (GTK_IS_ENTRY_COMPLETION (completion));
1377   g_return_if_fail (index_ >= 0);
1378
1379   gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (completion->priv->actions),
1380                                  &iter, NULL, index_);
1381   gtk_list_store_remove (completion->priv->actions, &iter);
1382 }
1383
1384 /**
1385  * gtk_entry_completion_set_text_column:
1386  * @completion: a #GtkEntryCompletion
1387  * @column: the column in the model of @completion to get strings from
1388  *
1389  * Convenience function for setting up the most used case of this code: a
1390  * completion list with just strings. This function will set up @completion
1391  * to have a list displaying all (and just) strings in the completion list,
1392  * and to get those strings from @column in the model of @completion.
1393  *
1394  * This functions creates and adds a #GtkCellRendererText for the selected
1395  * column. If you need to set the text column, but don't want the cell
1396  * renderer, use g_object_set() to set the #GtkEntryCompletion:text-column
1397  * property directly.
1398  *
1399  * Since: 2.4
1400  */
1401 void
1402 gtk_entry_completion_set_text_column (GtkEntryCompletion *completion,
1403                                       gint                column)
1404 {
1405   GtkCellRenderer *cell;
1406
1407   g_return_if_fail (GTK_IS_ENTRY_COMPLETION (completion));
1408   g_return_if_fail (column >= 0);
1409
1410   completion->priv->text_column = column;
1411
1412   cell = gtk_cell_renderer_text_new ();
1413   gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (completion),
1414                               cell, TRUE);
1415   gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (completion),
1416                                  cell,
1417                                  "text", column);
1418
1419   g_object_notify (G_OBJECT (completion), "text-column");
1420 }
1421
1422 /**
1423  * gtk_entry_completion_get_text_column:
1424  * @completion: a #GtkEntryCompletion
1425  *
1426  * Returns the column in the model of @completion to get strings from.
1427  *
1428  * Return value: the column containing the strings
1429  *
1430  * Since: 2.6
1431  */
1432 gint
1433 gtk_entry_completion_get_text_column (GtkEntryCompletion *completion)
1434 {
1435   g_return_val_if_fail (GTK_IS_ENTRY_COMPLETION (completion), -1);
1436
1437   return completion->priv->text_column;
1438 }
1439
1440 /* private */
1441
1442 static gboolean
1443 gtk_entry_completion_list_enter_notify (GtkWidget        *widget,
1444                                         GdkEventCrossing *event,
1445                                         gpointer          data)
1446 {
1447   GtkEntryCompletion *completion = GTK_ENTRY_COMPLETION (data);
1448
1449   return completion->priv->ignore_enter;
1450 }
1451
1452 static gboolean
1453 gtk_entry_completion_list_motion_notify (GtkWidget      *widget,
1454                                          GdkEventMotion *event,
1455                                          gpointer        data)
1456 {
1457   GtkEntryCompletion *completion = GTK_ENTRY_COMPLETION (data);
1458
1459   completion->priv->ignore_enter = FALSE;
1460
1461   return FALSE;
1462 }
1463
1464
1465 /* some nasty size requisition */
1466 gboolean
1467 _gtk_entry_completion_resize_popup (GtkEntryCompletion *completion)
1468 {
1469   GtkAllocation allocation;
1470   gint x, y;
1471   gint matches, actions, items, height;
1472   GdkScreen *screen;
1473   gint monitor_num;
1474   gint vertical_separator;
1475   GdkRectangle monitor;
1476   GdkWindow *window;
1477   GtkRequisition popup_req;
1478   GtkRequisition entry_req;
1479   GtkTreePath *path;
1480   gboolean above;
1481   gint width;
1482   GtkTreeViewColumn *action_column;
1483   gint action_height;
1484
1485   window = gtk_widget_get_window (completion->priv->entry);
1486
1487   if (!window)
1488     return FALSE;
1489
1490   gtk_widget_get_allocation (completion->priv->entry, &allocation);
1491   gtk_widget_get_preferred_size (completion->priv->entry,
1492                                  &entry_req, NULL);
1493
1494   gdk_window_get_origin (window, &x, &y);
1495   x += allocation.x;
1496   y += allocation.y + (allocation.height - entry_req.height) / 2;
1497
1498   matches = gtk_tree_model_iter_n_children (GTK_TREE_MODEL (completion->priv->filter_model), NULL);
1499   actions = gtk_tree_model_iter_n_children (GTK_TREE_MODEL (completion->priv->actions), NULL);
1500   action_column  = gtk_tree_view_get_column (GTK_TREE_VIEW (completion->priv->action_view), 0);
1501
1502   gtk_tree_view_column_cell_get_size (completion->priv->column, NULL,
1503                                       NULL, NULL, NULL, &height);
1504   gtk_tree_view_column_cell_get_size (action_column, NULL,
1505                                       NULL, NULL, NULL, &action_height);
1506
1507   gtk_widget_style_get (GTK_WIDGET (completion->priv->tree_view),
1508                         "vertical-separator", &vertical_separator,
1509                         NULL);
1510
1511   height += vertical_separator;
1512
1513   gtk_widget_realize (completion->priv->tree_view);
1514
1515   screen = gtk_widget_get_screen (GTK_WIDGET (completion->priv->entry));
1516   monitor_num = gdk_screen_get_monitor_at_window (screen, window);
1517   gdk_screen_get_monitor_workarea (screen, monitor_num, &monitor);
1518
1519   if (height == 0)
1520     items = 0;
1521   else if (y > monitor.height / 2)
1522     items = MIN (matches, (((monitor.y + y) - (actions * action_height)) / height) - 1);
1523   else
1524     items = MIN (matches, (((monitor.height - y) - (actions * action_height)) / height) - 1);
1525
1526   if (items <= 0)
1527     gtk_widget_hide (completion->priv->scrolled_window);
1528   else
1529     gtk_widget_show (completion->priv->scrolled_window);
1530
1531   if (completion->priv->popup_set_width)
1532     width = MIN (allocation.width, monitor.width);
1533   else
1534     width = -1;
1535
1536   gtk_tree_view_columns_autosize (GTK_TREE_VIEW (completion->priv->tree_view));
1537   gtk_scrolled_window_set_min_content_width (GTK_SCROLLED_WINDOW (completion->priv->scrolled_window), width);
1538   gtk_widget_set_size_request (completion->priv->popup_window, width, -1);
1539   gtk_scrolled_window_set_min_content_height (GTK_SCROLLED_WINDOW (completion->priv->scrolled_window), items * height);
1540
1541   if (actions)
1542     gtk_widget_show (completion->priv->action_view);
1543   else
1544     gtk_widget_hide (completion->priv->action_view);
1545
1546   gtk_widget_get_preferred_size (completion->priv->popup_window,
1547                                  &popup_req, NULL);
1548
1549   if (x < monitor.x)
1550     x = monitor.x;
1551   else if (x + popup_req.width > monitor.x + monitor.width)
1552     x = monitor.x + monitor.width - popup_req.width;
1553
1554   if (y + entry_req.height + popup_req.height <= monitor.y + monitor.height ||
1555       y - monitor.y < (monitor.y + monitor.height) - (y + entry_req.height))
1556     {
1557       y += entry_req.height;
1558       above = FALSE;
1559     }
1560   else
1561     {
1562       y -= popup_req.height;
1563       above = TRUE;
1564     }
1565
1566   if (matches > 0)
1567     {
1568       path = gtk_tree_path_new_from_indices (above ? matches - 1 : 0, -1);
1569       gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (completion->priv->tree_view), path,
1570                                     NULL, FALSE, 0.0, 0.0);
1571       gtk_tree_path_free (path);
1572     }
1573
1574   gtk_window_move (GTK_WINDOW (completion->priv->popup_window), x, y);
1575
1576   return above;
1577 }
1578
1579 void
1580 _gtk_entry_completion_popup (GtkEntryCompletion *completion,
1581                              GdkDevice          *device)
1582 {
1583   GtkTreeViewColumn *column;
1584   GtkStyleContext *context;
1585   GdkRGBA color;
1586   GList *renderers;
1587   GtkWidget *toplevel;
1588
1589   if (gtk_widget_get_mapped (completion->priv->popup_window))
1590     return;
1591
1592   if (!gtk_widget_get_mapped (completion->priv->entry))
1593     return;
1594
1595   if (!gtk_widget_has_focus (completion->priv->entry))
1596     return;
1597
1598   if (completion->priv->grab_device)
1599     return;
1600
1601   completion->priv->ignore_enter = TRUE;
1602
1603   column = gtk_tree_view_get_column (GTK_TREE_VIEW (completion->priv->action_view), 0);
1604   renderers = gtk_cell_layout_get_cells (GTK_CELL_LAYOUT (column));
1605
1606   context = gtk_widget_get_style_context (completion->priv->tree_view);
1607   gtk_style_context_get_background_color (context, 0, &color);
1608
1609   g_object_set (GTK_CELL_RENDERER (renderers->data),
1610                 "cell-background-rgba", &color,
1611                 NULL);
1612   g_list_free (renderers);
1613
1614   gtk_widget_show_all (completion->priv->vbox);
1615
1616   /* default on no match */
1617   completion->priv->current_selected = -1;
1618
1619   _gtk_entry_completion_resize_popup (completion);
1620
1621   toplevel = gtk_widget_get_toplevel (completion->priv->entry);
1622   if (GTK_IS_WINDOW (toplevel))
1623     gtk_window_group_add_window (gtk_window_get_group (GTK_WINDOW (toplevel)),
1624                                  GTK_WINDOW (completion->priv->popup_window));
1625
1626   /* prevent the first row being focused */
1627   gtk_widget_grab_focus (completion->priv->tree_view);
1628
1629   gtk_tree_selection_unselect_all (gtk_tree_view_get_selection (GTK_TREE_VIEW (completion->priv->tree_view)));
1630   gtk_tree_selection_unselect_all (gtk_tree_view_get_selection (GTK_TREE_VIEW (completion->priv->action_view)));
1631
1632   gtk_window_set_screen (GTK_WINDOW (completion->priv->popup_window),
1633                          gtk_widget_get_screen (completion->priv->entry));
1634
1635   gtk_widget_show (completion->priv->popup_window);
1636
1637   gtk_device_grab_add (completion->priv->popup_window, device, TRUE);
1638   gdk_device_grab (device, gtk_widget_get_window (completion->priv->popup_window),
1639                    GDK_OWNERSHIP_WINDOW, TRUE,
1640                    GDK_BUTTON_PRESS_MASK |
1641                    GDK_BUTTON_RELEASE_MASK |
1642                    GDK_POINTER_MOTION_MASK,
1643                    NULL, GDK_CURRENT_TIME);
1644
1645   completion->priv->grab_device = device;
1646 }
1647
1648 void
1649 _gtk_entry_completion_popdown (GtkEntryCompletion *completion)
1650 {
1651   if (!gtk_widget_get_mapped (completion->priv->popup_window))
1652     return;
1653
1654   completion->priv->ignore_enter = FALSE;
1655
1656   if (completion->priv->grab_device)
1657     {
1658       gdk_device_ungrab (completion->priv->grab_device, GDK_CURRENT_TIME);
1659       gtk_device_grab_remove (completion->priv->popup_window,
1660                               completion->priv->grab_device);
1661       completion->priv->grab_device = NULL;
1662     }
1663
1664   gtk_widget_hide (completion->priv->popup_window);
1665 }
1666
1667 static gboolean
1668 gtk_entry_completion_match_selected (GtkEntryCompletion *completion,
1669                                      GtkTreeModel       *model,
1670                                      GtkTreeIter        *iter)
1671 {
1672   gchar *str = NULL;
1673
1674   gtk_tree_model_get (model, iter, completion->priv->text_column, &str, -1);
1675   gtk_entry_set_text (GTK_ENTRY (completion->priv->entry), str ? str : "");
1676
1677   /* move cursor to the end */
1678   gtk_editable_set_position (GTK_EDITABLE (completion->priv->entry), -1);
1679
1680   g_free (str);
1681
1682   return TRUE;
1683 }
1684
1685 static gboolean
1686 gtk_entry_completion_cursor_on_match (GtkEntryCompletion *completion,
1687                                       GtkTreeModel       *model,
1688                                       GtkTreeIter        *iter)
1689 {
1690   gtk_entry_completion_insert_completion (completion, model, iter);
1691
1692   return TRUE;
1693 }
1694
1695 /**
1696  * gtk_entry_completion_compute_prefix:
1697  * @completion: the entry completion
1698  * @key: The text to complete for
1699  *
1700  * Computes the common prefix that is shared by all rows in @completion
1701  * that start with @key. If no row matches @key, %NULL will be returned.
1702  * Note that a text column must have been set for this function to work,
1703  * see gtk_entry_completion_set_text_column() for details. 
1704  *
1705  * Returns: (transfer full): The common prefix all rows starting with @key
1706  *   or %NULL if no row matches @key.
1707  *
1708  * Since: 3.4
1709  **/
1710 gchar *
1711 gtk_entry_completion_compute_prefix (GtkEntryCompletion *completion,
1712                                      const char         *key)
1713 {
1714   GtkTreeIter iter;
1715   gchar *prefix = NULL;
1716   gboolean valid;
1717
1718   if (completion->priv->text_column < 0)
1719     return NULL;
1720
1721   valid = gtk_tree_model_get_iter_first (GTK_TREE_MODEL (completion->priv->filter_model),
1722                                          &iter);
1723
1724   while (valid)
1725     {
1726       gchar *text;
1727
1728       gtk_tree_model_get (GTK_TREE_MODEL (completion->priv->filter_model),
1729                           &iter, completion->priv->text_column, &text,
1730                           -1);
1731
1732       if (text && g_str_has_prefix (text, key))
1733         {
1734           if (!prefix)
1735             prefix = g_strdup (text);
1736           else
1737             {
1738               gchar *p = prefix;
1739               gchar *q = text;
1740
1741               while (*p && *p == *q)
1742                 {
1743                   p++;
1744                   q++;
1745                 }
1746
1747               *p = '\0';
1748
1749               if (p > prefix)
1750                 {
1751                   /* strip a partial multibyte character */
1752                   q = g_utf8_find_prev_char (prefix, p);
1753                   switch (g_utf8_get_char_validated (q, p - q))
1754                     {
1755                     case (gunichar)-2:
1756                     case (gunichar)-1:
1757                       *q = 0;
1758                     default: ;
1759                     }
1760                 }
1761             }
1762         }
1763
1764       g_free (text);
1765       valid = gtk_tree_model_iter_next (GTK_TREE_MODEL (completion->priv->filter_model),
1766                                         &iter);
1767     }
1768
1769   return prefix;
1770 }
1771
1772
1773 static gboolean
1774 gtk_entry_completion_real_insert_prefix (GtkEntryCompletion *completion,
1775                                          const gchar        *prefix)
1776 {
1777   if (prefix)
1778     {
1779       gint key_len;
1780       gint prefix_len;
1781       const gchar *key;
1782
1783       prefix_len = g_utf8_strlen (prefix, -1);
1784
1785       key = gtk_entry_get_text (GTK_ENTRY (completion->priv->entry));
1786       key_len = g_utf8_strlen (key, -1);
1787
1788       if (prefix_len > key_len)
1789         {
1790           gint pos = prefix_len;
1791
1792           gtk_editable_insert_text (GTK_EDITABLE (completion->priv->entry),
1793                                     prefix + strlen (key), -1, &pos);
1794           gtk_editable_select_region (GTK_EDITABLE (completion->priv->entry),
1795                                       key_len, prefix_len);
1796
1797           completion->priv->has_completion = TRUE;
1798         }
1799     }
1800
1801   return TRUE;
1802 }
1803
1804 /**
1805  * gtk_entry_completion_get_completion_prefix:
1806  * @completion: a #GtkEntryCompletion
1807  *
1808  * Get the original text entered by the user that triggered
1809  * the completion or %NULL if there's no completion ongoing.
1810  *
1811  * Returns: the prefix for the current completion
1812  *
1813  * Since: 2.12
1814  */
1815 const gchar*
1816 gtk_entry_completion_get_completion_prefix (GtkEntryCompletion *completion)
1817 {
1818   g_return_val_if_fail (GTK_IS_ENTRY_COMPLETION (completion), NULL);
1819
1820   return completion->priv->completion_prefix;
1821 }
1822
1823 static void
1824 gtk_entry_completion_insert_completion_text (GtkEntryCompletion *completion,
1825                                              const gchar *text)
1826 {
1827   GtkEntryCompletionPrivate *priv = completion->priv;
1828   gint len;
1829
1830   priv = completion->priv;
1831
1832   if (priv->changed_id > 0)
1833     g_signal_handler_block (priv->entry, priv->changed_id);
1834
1835   if (priv->insert_text_id > 0)
1836     g_signal_handler_block (priv->entry, priv->insert_text_id);
1837
1838   gtk_entry_set_text (GTK_ENTRY (priv->entry), text);
1839
1840   len = strlen (priv->completion_prefix);
1841   gtk_editable_select_region (GTK_EDITABLE (priv->entry), len, -1);
1842
1843   if (priv->changed_id > 0)
1844     g_signal_handler_unblock (priv->entry, priv->changed_id);
1845
1846   if (priv->insert_text_id > 0)
1847     g_signal_handler_unblock (priv->entry, priv->insert_text_id);
1848 }
1849
1850 static gboolean
1851 gtk_entry_completion_insert_completion (GtkEntryCompletion *completion,
1852                                         GtkTreeModel       *model,
1853                                         GtkTreeIter        *iter)
1854 {
1855   gchar *str = NULL;
1856
1857   if (completion->priv->text_column < 0)
1858     return FALSE;
1859
1860   gtk_tree_model_get (model, iter,
1861                       completion->priv->text_column, &str,
1862                       -1);
1863
1864   gtk_entry_completion_insert_completion_text (completion, str);
1865
1866   g_free (str);
1867
1868   return TRUE;
1869 }
1870
1871 /**
1872  * gtk_entry_completion_insert_prefix:
1873  * @completion: a #GtkEntryCompletion
1874  *
1875  * Requests a prefix insertion.
1876  *
1877  * Since: 2.6
1878  */
1879 void
1880 gtk_entry_completion_insert_prefix (GtkEntryCompletion *completion)
1881 {
1882   gboolean done;
1883   gchar *prefix;
1884
1885   if (completion->priv->insert_text_id > 0)
1886     g_signal_handler_block (completion->priv->entry,
1887                             completion->priv->insert_text_id);
1888
1889   prefix = gtk_entry_completion_compute_prefix (completion,
1890                                                 gtk_entry_get_text (GTK_ENTRY (completion->priv->entry)));
1891
1892   if (prefix)
1893     {
1894       g_signal_emit (completion, entry_completion_signals[INSERT_PREFIX],
1895                      0, prefix, &done);
1896       g_free (prefix);
1897     }
1898
1899   if (completion->priv->insert_text_id > 0)
1900     g_signal_handler_unblock (completion->priv->entry,
1901                               completion->priv->insert_text_id);
1902 }
1903
1904 /**
1905  * gtk_entry_completion_set_inline_completion:
1906  * @completion: a #GtkEntryCompletion
1907  * @inline_completion: %TRUE to do inline completion
1908  *
1909  * Sets whether the common prefix of the possible completions should
1910  * be automatically inserted in the entry.
1911  *
1912  * Since: 2.6
1913  */
1914 void
1915 gtk_entry_completion_set_inline_completion (GtkEntryCompletion *completion,
1916                                             gboolean            inline_completion)
1917 {
1918   g_return_if_fail (GTK_IS_ENTRY_COMPLETION (completion));
1919
1920   inline_completion = inline_completion != FALSE;
1921
1922   if (completion->priv->inline_completion != inline_completion)
1923     {
1924       completion->priv->inline_completion = inline_completion;
1925
1926       g_object_notify (G_OBJECT (completion), "inline-completion");
1927     }
1928 }
1929
1930 /**
1931  * gtk_entry_completion_get_inline_completion:
1932  * @completion: a #GtkEntryCompletion
1933  *
1934  * Returns whether the common prefix of the possible completions should
1935  * be automatically inserted in the entry.
1936  *
1937  * Return value: %TRUE if inline completion is turned on
1938  *
1939  * Since: 2.6
1940  */
1941 gboolean
1942 gtk_entry_completion_get_inline_completion (GtkEntryCompletion *completion)
1943 {
1944   g_return_val_if_fail (GTK_IS_ENTRY_COMPLETION (completion), FALSE);
1945
1946   return completion->priv->inline_completion;
1947 }
1948
1949 /**
1950  * gtk_entry_completion_set_popup_completion:
1951  * @completion: a #GtkEntryCompletion
1952  * @popup_completion: %TRUE to do popup completion
1953  *
1954  * Sets whether the completions should be presented in a popup window.
1955  *
1956  * Since: 2.6
1957  */
1958 void
1959 gtk_entry_completion_set_popup_completion (GtkEntryCompletion *completion,
1960                                            gboolean            popup_completion)
1961 {
1962   g_return_if_fail (GTK_IS_ENTRY_COMPLETION (completion));
1963
1964   popup_completion = popup_completion != FALSE;
1965
1966   if (completion->priv->popup_completion != popup_completion)
1967     {
1968       completion->priv->popup_completion = popup_completion;
1969
1970       g_object_notify (G_OBJECT (completion), "popup-completion");
1971     }
1972 }
1973
1974
1975 /**
1976  * gtk_entry_completion_get_popup_completion:
1977  * @completion: a #GtkEntryCompletion
1978  *
1979  * Returns whether the completions should be presented in a popup window.
1980  *
1981  * Return value: %TRUE if popup completion is turned on
1982  *
1983  * Since: 2.6
1984  */
1985 gboolean
1986 gtk_entry_completion_get_popup_completion (GtkEntryCompletion *completion)
1987 {
1988   g_return_val_if_fail (GTK_IS_ENTRY_COMPLETION (completion), TRUE);
1989
1990   return completion->priv->popup_completion;
1991 }
1992
1993 /**
1994  * gtk_entry_completion_set_popup_set_width:
1995  * @completion: a #GtkEntryCompletion
1996  * @popup_set_width: %TRUE to make the width of the popup the same as the entry
1997  *
1998  * Sets whether the completion popup window will be resized to be the same
1999  * width as the entry.
2000  *
2001  * Since: 2.8
2002  */
2003 void
2004 gtk_entry_completion_set_popup_set_width (GtkEntryCompletion *completion,
2005                                           gboolean            popup_set_width)
2006 {
2007   g_return_if_fail (GTK_IS_ENTRY_COMPLETION (completion));
2008
2009   popup_set_width = popup_set_width != FALSE;
2010
2011   if (completion->priv->popup_set_width != popup_set_width)
2012     {
2013       completion->priv->popup_set_width = popup_set_width;
2014
2015       g_object_notify (G_OBJECT (completion), "popup-set-width");
2016     }
2017 }
2018
2019 /**
2020  * gtk_entry_completion_get_popup_set_width:
2021  * @completion: a #GtkEntryCompletion
2022  *
2023  * Returns whether the  completion popup window will be resized to the
2024  * width of the entry.
2025  *
2026  * Return value: %TRUE if the popup window will be resized to the width of
2027  *   the entry
2028  *
2029  * Since: 2.8
2030  */
2031 gboolean
2032 gtk_entry_completion_get_popup_set_width (GtkEntryCompletion *completion)
2033 {
2034   g_return_val_if_fail (GTK_IS_ENTRY_COMPLETION (completion), TRUE);
2035
2036   return completion->priv->popup_set_width;
2037 }
2038
2039
2040 /**
2041  * gtk_entry_completion_set_popup_single_match:
2042  * @completion: a #GtkEntryCompletion
2043  * @popup_single_match: %TRUE if the popup should appear even for a single
2044  *     match
2045  *
2046  * Sets whether the completion popup window will appear even if there is
2047  * only a single match. You may want to set this to %FALSE if you
2048  * are using <link linkend="GtkEntryCompletion--inline-completion">inline
2049  * completion</link>.
2050  *
2051  * Since: 2.8
2052  */
2053 void
2054 gtk_entry_completion_set_popup_single_match (GtkEntryCompletion *completion,
2055                                              gboolean            popup_single_match)
2056 {
2057   g_return_if_fail (GTK_IS_ENTRY_COMPLETION (completion));
2058
2059   popup_single_match = popup_single_match != FALSE;
2060
2061   if (completion->priv->popup_single_match != popup_single_match)
2062     {
2063       completion->priv->popup_single_match = popup_single_match;
2064
2065       g_object_notify (G_OBJECT (completion), "popup-single-match");
2066     }
2067 }
2068
2069 /**
2070  * gtk_entry_completion_get_popup_single_match:
2071  * @completion: a #GtkEntryCompletion
2072  *
2073  * Returns whether the completion popup window will appear even if there is
2074  * only a single match.
2075  *
2076  * Return value: %TRUE if the popup window will appear regardless of the
2077  *    number of matches
2078  *
2079  * Since: 2.8
2080  */
2081 gboolean
2082 gtk_entry_completion_get_popup_single_match (GtkEntryCompletion *completion)
2083 {
2084   g_return_val_if_fail (GTK_IS_ENTRY_COMPLETION (completion), TRUE);
2085
2086   return completion->priv->popup_single_match;
2087 }
2088
2089 /**
2090  * gtk_entry_completion_set_inline_selection:
2091  * @completion: a #GtkEntryCompletion
2092  * @inline_selection: %TRUE to do inline selection
2093  *
2094  * Sets whether it is possible to cycle through the possible completions
2095  * inside the entry.
2096  *
2097  * Since: 2.12
2098  */
2099 void
2100 gtk_entry_completion_set_inline_selection (GtkEntryCompletion *completion,
2101                                            gboolean inline_selection)
2102 {
2103   g_return_if_fail (GTK_IS_ENTRY_COMPLETION (completion));
2104
2105   inline_selection = inline_selection != FALSE;
2106
2107   if (completion->priv->inline_selection != inline_selection)
2108     {
2109       completion->priv->inline_selection = inline_selection;
2110
2111       g_object_notify (G_OBJECT (completion), "inline-selection");
2112     }
2113 }
2114
2115 /**
2116  * gtk_entry_completion_get_inline_selection:
2117  * @completion: a #GtkEntryCompletion
2118  *
2119  * Returns %TRUE if inline-selection mode is turned on.
2120  *
2121  * Returns: %TRUE if inline-selection mode is on
2122  *
2123  * Since: 2.12
2124  */
2125 gboolean
2126 gtk_entry_completion_get_inline_selection (GtkEntryCompletion *completion)
2127 {
2128   g_return_val_if_fail (GTK_IS_ENTRY_COMPLETION (completion), FALSE);
2129
2130   return completion->priv->inline_selection;
2131 }