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