]> Pileus Git - ~andy/gtk/blob - gtk/gtkentrycompletion.c
Require glib 2.6.0 for g_filename_display_basename.
[~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 "gtkalias.h"
22 #include "gtkentrycompletion.h"
23 #include "gtkentryprivate.h"
24 #include "gtkcelllayout.h"
25
26 #include "gtkintl.h"
27 #include "gtkcellrenderertext.h"
28 #include "gtkframe.h"
29 #include "gtktreeselection.h"
30 #include "gtktreeview.h"
31 #include "gtkscrolledwindow.h"
32 #include "gtkvbox.h"
33 #include "gtkwindow.h"
34 #include "gtkentry.h"
35 #include "gtkmain.h"
36 #include "gtksignal.h"
37 #include "gtkmarshalers.h"
38
39 #include <string.h>
40
41
42 /* signals */
43 enum
44 {
45   INSERT_PREFIX,
46   MATCH_SELECTED,
47   ACTION_ACTIVATED,
48   LAST_SIGNAL
49 };
50
51 /* properties */
52 enum
53 {
54   PROP_0,
55   PROP_MODEL,
56   PROP_MINIMUM_KEY_LENGTH,
57   PROP_TEXT_COLUMN,
58   PROP_INLINE_COMPLETION,
59   PROP_POPUP_COMPLETION
60 };
61
62 #define GTK_ENTRY_COMPLETION_GET_PRIVATE(obj)(G_TYPE_INSTANCE_GET_PRIVATE ((obj), GTK_TYPE_ENTRY_COMPLETION, GtkEntryCompletionPrivate))
63
64 static void     gtk_entry_completion_class_init          (GtkEntryCompletionClass *klass);
65 static void     gtk_entry_completion_cell_layout_init    (GtkCellLayoutIface      *iface);
66 static void     gtk_entry_completion_init                (GtkEntryCompletion      *completion);
67 static void     gtk_entry_completion_set_property        (GObject                 *object,
68                                                           guint                    prop_id,
69                                                           const GValue            *value,
70                                                           GParamSpec              *pspec);
71 static void     gtk_entry_completion_get_property        (GObject                 *object,
72                                                           guint                    prop_id,
73                                                           GValue                  *value,
74                                                           GParamSpec              *pspec);
75 static void     gtk_entry_completion_finalize            (GObject                 *object);
76
77 static void     gtk_entry_completion_pack_start          (GtkCellLayout           *cell_layout,
78                                                           GtkCellRenderer         *cell,
79                                                           gboolean                 expand);
80 static void     gtk_entry_completion_pack_end            (GtkCellLayout           *cell_layout,
81                                                           GtkCellRenderer         *cell,
82                                                           gboolean                 expand);
83 static void     gtk_entry_completion_clear               (GtkCellLayout           *cell_layout);
84 static void     gtk_entry_completion_add_attribute       (GtkCellLayout           *cell_layout,
85                                                           GtkCellRenderer         *cell,
86                                                           const char              *attribute,
87                                                           gint                     column);
88 static void     gtk_entry_completion_set_cell_data_func  (GtkCellLayout           *cell_layout,
89                                                           GtkCellRenderer         *cell,
90                                                           GtkCellLayoutDataFunc    func,
91                                                           gpointer                 func_data,
92                                                           GDestroyNotify           destroy);
93 static void     gtk_entry_completion_clear_attributes    (GtkCellLayout           *cell_layout,
94                                                           GtkCellRenderer         *cell);
95 static void     gtk_entry_completion_reorder             (GtkCellLayout           *cell_layout,
96                                                           GtkCellRenderer         *cell,
97                                                           gint                     position);
98
99 static gboolean gtk_entry_completion_visible_func        (GtkTreeModel            *model,
100                                                           GtkTreeIter             *iter,
101                                                           gpointer                 data);
102 static gboolean gtk_entry_completion_popup_key_press     (GtkWidget               *widget,
103                                                           GdkEventKey             *event,
104                                                           gpointer                 user_data);
105 static gboolean gtk_entry_completion_popup_button_press  (GtkWidget               *widget,
106                                                           GdkEventButton          *event,
107                                                           gpointer                 user_data);
108 static gboolean gtk_entry_completion_list_button_press   (GtkWidget               *widget,
109                                                           GdkEventButton          *event,
110                                                           gpointer                 user_data);
111 static gboolean gtk_entry_completion_action_button_press (GtkWidget               *widget,
112                                                           GdkEventButton          *event,
113                                                           gpointer                 user_data);
114 static void     gtk_entry_completion_selection_changed   (GtkTreeSelection        *selection,
115                                                           gpointer                 data);
116 static gboolean gtk_entry_completion_list_enter_notify   (GtkWidget               *widget,
117                                                           GdkEventCrossing        *event,
118                                                           gpointer                 data);
119 static gboolean gtk_entry_completion_list_motion_notify  (GtkWidget               *widget,
120                                                           GdkEventMotion          *event,
121                                                           gpointer                 data);
122 static void     gtk_entry_completion_insert_action       (GtkEntryCompletion      *completion,
123                                                           gint                     index,
124                                                           const gchar             *string,
125                                                           gboolean                 markup);
126 static void     gtk_entry_completion_action_data_func    (GtkTreeViewColumn       *tree_column,
127                                                           GtkCellRenderer         *cell,
128                                                           GtkTreeModel            *model,
129                                                           GtkTreeIter             *iter,
130                                                           gpointer                 data);
131
132 static gboolean gtk_entry_completion_match_selected      (GtkEntryCompletion *completion,
133                                                           GtkTreeModel       *model,
134                                                           GtkTreeIter        *iter);
135 static gboolean gtk_entry_completion_real_insert_prefix  (GtkEntryCompletion *completion,
136                                                           const gchar        *prefix);
137
138 static GObjectClass *parent_class = NULL;
139 static guint entry_completion_signals[LAST_SIGNAL] = { 0 };
140
141
142 GType
143 gtk_entry_completion_get_type (void)
144 {
145   static GType entry_completion_type = 0;
146
147   if (!entry_completion_type)
148     {
149       static const GTypeInfo entry_completion_info =
150       {
151         sizeof (GtkEntryCompletionClass),
152         NULL,
153         NULL,
154         (GClassInitFunc) gtk_entry_completion_class_init,
155         NULL,
156         NULL,
157         sizeof (GtkEntryCompletion),
158         0,
159         (GInstanceInitFunc) gtk_entry_completion_init
160       };
161
162       static const GInterfaceInfo cell_layout_info =
163       {
164         (GInterfaceInitFunc) gtk_entry_completion_cell_layout_init,
165         NULL,
166         NULL
167       };
168
169       entry_completion_type =
170         g_type_register_static (G_TYPE_OBJECT, "GtkEntryCompletion",
171                                 &entry_completion_info, 0);
172
173       g_type_add_interface_static (entry_completion_type,
174                                    GTK_TYPE_CELL_LAYOUT,
175                                    &cell_layout_info);
176     }
177
178   return entry_completion_type;
179 }
180
181 static void
182 gtk_entry_completion_class_init (GtkEntryCompletionClass *klass)
183 {
184   GObjectClass *object_class;
185
186   parent_class = g_type_class_peek_parent (klass);
187   object_class = (GObjectClass *)klass;
188
189   object_class->set_property = gtk_entry_completion_set_property;
190   object_class->get_property = gtk_entry_completion_get_property;
191   object_class->finalize = gtk_entry_completion_finalize;
192
193   klass->match_selected = gtk_entry_completion_match_selected;
194   klass->insert_prefix = gtk_entry_completion_real_insert_prefix;
195
196   /**
197    * GtkEntryCompletion::insert-prefix:
198    * @widget: the object which received the signal
199    * @prefix: the common prefix of all possible completions
200    * 
201    * Gets emitted when the inline autocompletion is triggered. 
202    * The default behaviour is to make the entry display the 
203    * whole prefix and select the newly inserted part.
204    *
205    * Applications may connect to this signal in order to insert only a
206    * smaller part of the @prefix into the entry - e.g. the entry used in
207    * the #GtkFileChooser inserts only the part of the prefix up to the 
208    * next '/'.
209    *
210    * Return value: %TRUE if the signal has been handled
211    * 
212    * Since: 2.6
213    */ 
214   entry_completion_signals[INSERT_PREFIX] =
215     g_signal_new ("insert_prefix",
216                   G_TYPE_FROM_CLASS (klass),
217                   G_SIGNAL_RUN_LAST,
218                   G_STRUCT_OFFSET (GtkEntryCompletionClass, insert_prefix),
219                   _gtk_boolean_handled_accumulator, NULL,
220                   _gtk_marshal_BOOLEAN__STRING,
221                   G_TYPE_BOOLEAN, 1,
222                   G_TYPE_STRING);
223
224   /**
225    * GtkEntryCompletion::match-selected:
226    * @widget: the object which received the signal
227    * @model: the #GtkTreeModel containing the matches
228    * @iter: a #GtkTreeIter positioned at the selected match
229    * 
230    * Gets emitted when a match from the list is selected. 
231    * The default behaviour is to replace the contents of the 
232    * entry with the contents of the text column in the row 
233    * pointed to by @iter.
234    *
235    * Return value: %TRUE if the signal has been handled
236    * 
237    * Since: 2.4
238    */ 
239   entry_completion_signals[MATCH_SELECTED] =
240     g_signal_new ("match_selected",
241                   G_TYPE_FROM_CLASS (klass),
242                   G_SIGNAL_RUN_LAST,
243                   G_STRUCT_OFFSET (GtkEntryCompletionClass, match_selected),
244                   _gtk_boolean_handled_accumulator, NULL,
245                   _gtk_marshal_BOOLEAN__OBJECT_BOXED,
246                   G_TYPE_BOOLEAN, 2,
247                   GTK_TYPE_TREE_MODEL,
248                   GTK_TYPE_TREE_ITER);
249                   
250   /**
251    * GtkEntryCompletion::action-activated:
252    * @widget: the object which received the signal
253    * @index: the index of the activated action
254    *
255    * Gets emitted when an action is activated.
256    * 
257    * Since: 2.4
258    */
259   entry_completion_signals[ACTION_ACTIVATED] =
260     g_signal_new ("action_activated",
261                   G_TYPE_FROM_CLASS (klass),
262                   G_SIGNAL_RUN_LAST,
263                   G_STRUCT_OFFSET (GtkEntryCompletionClass, action_activated),
264                   NULL, NULL,
265                   _gtk_marshal_NONE__INT,
266                   G_TYPE_NONE, 1,
267                   G_TYPE_INT);
268
269   g_object_class_install_property (object_class,
270                                    PROP_MODEL,
271                                    g_param_spec_object ("model",
272                                                         P_("Completion Model"),
273                                                         P_("The model to find matches in"),
274                                                         GTK_TYPE_TREE_MODEL,
275                                                         G_PARAM_READWRITE));
276   g_object_class_install_property (object_class,
277                                    PROP_MINIMUM_KEY_LENGTH,
278                                    g_param_spec_int ("minimum_key_length",
279                                                      P_("Minimum Key Length"),
280                                                      P_("Minimum length of the search key in order to look up matches"),
281                                                      -1,
282                                                      G_MAXINT,
283                                                      1,
284                                                      G_PARAM_READWRITE));
285   /**
286    * GtkEntryCompletion:text-column:
287    *
288    * The column of the model containing the strings.
289    *
290    * Since: 2.6
291    */
292   g_object_class_install_property (object_class,
293                                    PROP_TEXT_COLUMN,
294                                    g_param_spec_int ("text_column",
295                                                      P_("Text column"),
296                                                      P_("The column of the model containing the strings."),
297                                                      -1,
298                                                      G_MAXINT,
299                                                      -1,
300                                                      G_PARAM_READWRITE));
301
302   /**
303    * GtkEntryCompletion:inline-completion:
304    * 
305    * Determines whether the common prefix of the possible completions 
306    * should be inserted automatically in the entry.
307    *
308    * Since: 2.6
309    **/
310   g_object_class_install_property (object_class,
311                                    PROP_INLINE_COMPLETION,
312                                    g_param_spec_boolean ("inline_completion",
313                                                          P_("Inline completion"),
314                                                          P_("Whether the common prefix should be inserted automatically"),
315                                                          FALSE,
316                                                          G_PARAM_READWRITE));
317   /**
318    * GtkEntryCompletion:popup-completion:
319    * 
320    * Determines whether the possible completions should be 
321    * shown in a popup window. 
322    *
323    * Since: 2.6
324    **/
325   g_object_class_install_property (object_class,
326                                    PROP_POPUP_COMPLETION,
327                                    g_param_spec_boolean ("popup_completion",
328                                                          P_("Popup completion"),
329                                                          P_("Whether the completions should be shown in a popup window"),
330                                                          TRUE,
331                                                          G_PARAM_READWRITE));
332
333   g_type_class_add_private (object_class, sizeof (GtkEntryCompletionPrivate));
334 }
335
336 static void
337 gtk_entry_completion_cell_layout_init (GtkCellLayoutIface *iface)
338 {
339   iface->pack_start = gtk_entry_completion_pack_start;
340   iface->pack_end = gtk_entry_completion_pack_end;
341   iface->clear = gtk_entry_completion_clear;
342   iface->add_attribute = gtk_entry_completion_add_attribute;
343   iface->set_cell_data_func = gtk_entry_completion_set_cell_data_func;
344   iface->clear_attributes = gtk_entry_completion_clear_attributes;
345   iface->reorder = gtk_entry_completion_reorder;
346 }
347
348 static void
349 gtk_entry_completion_init (GtkEntryCompletion *completion)
350 {
351   GtkCellRenderer *cell;
352   GtkTreeSelection *sel;
353   GtkEntryCompletionPrivate *priv;
354   GtkWidget *popup_frame;
355
356   /* yes, also priv, need to keep the code readable */
357   priv = completion->priv = GTK_ENTRY_COMPLETION_GET_PRIVATE (completion);
358
359   priv->minimum_key_length = 1;
360   priv->text_column = -1;
361   priv->has_completion = FALSE;
362   priv->inline_completion = FALSE;
363   priv->popup_completion = TRUE;
364
365   /* completions */
366   priv->filter_model = NULL;
367
368   priv->tree_view = gtk_tree_view_new ();
369   g_signal_connect (priv->tree_view, "button_press_event",
370                     G_CALLBACK (gtk_entry_completion_list_button_press),
371                     completion);
372   g_signal_connect (priv->tree_view, "enter_notify_event",
373                     G_CALLBACK (gtk_entry_completion_list_enter_notify),
374                     completion);
375   g_signal_connect (priv->tree_view, "motion_notify_event",
376                     G_CALLBACK (gtk_entry_completion_list_motion_notify),
377                     completion);
378   gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (priv->tree_view), FALSE);
379   gtk_tree_view_set_hover_selection (GTK_TREE_VIEW (priv->tree_view), TRUE);
380
381   sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->tree_view));
382   gtk_tree_selection_set_mode (sel, GTK_SELECTION_SINGLE);
383   gtk_tree_selection_unselect_all (sel);
384   g_signal_connect (sel, "changed",
385                     G_CALLBACK (gtk_entry_completion_selection_changed),
386                     completion);
387   priv->first_sel_changed = TRUE;
388
389   priv->column = gtk_tree_view_column_new ();
390   gtk_tree_view_append_column (GTK_TREE_VIEW (priv->tree_view), priv->column);
391
392   priv->scrolled_window = gtk_scrolled_window_new (NULL, NULL);
393   gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (priv->scrolled_window),
394                                   GTK_POLICY_NEVER,
395                                   GTK_POLICY_AUTOMATIC);
396   gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (priv->scrolled_window),
397                                        GTK_SHADOW_NONE);
398
399   /* a nasty hack to get the completions treeview to size nicely */
400   gtk_widget_set_size_request (GTK_SCROLLED_WINDOW (priv->scrolled_window)->vscrollbar, -1, 0);
401
402   /* actions */
403   priv->actions = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_BOOLEAN);
404
405   priv->action_view =
406     gtk_tree_view_new_with_model (GTK_TREE_MODEL (priv->actions));
407   g_signal_connect (priv->action_view, "button_press_event",
408                     G_CALLBACK (gtk_entry_completion_action_button_press),
409                     completion);
410   g_signal_connect (priv->action_view, "enter_notify_event",
411                     G_CALLBACK (gtk_entry_completion_list_enter_notify),
412                     completion);
413   g_signal_connect (priv->action_view, "motion_notify_event",
414                     G_CALLBACK (gtk_entry_completion_list_motion_notify),
415                     completion);
416   gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (priv->action_view), FALSE);
417   gtk_tree_view_set_hover_selection (GTK_TREE_VIEW (priv->action_view), TRUE);
418
419   sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->action_view));
420   gtk_tree_selection_set_mode (sel, GTK_SELECTION_SINGLE);
421   gtk_tree_selection_unselect_all (sel);
422
423   cell = gtk_cell_renderer_text_new ();
424   gtk_tree_view_insert_column_with_data_func (GTK_TREE_VIEW (priv->action_view),
425                                               0, "",
426                                               cell,
427                                               gtk_entry_completion_action_data_func,
428                                               NULL,
429                                               NULL);
430
431   /* pack it all */
432   priv->popup_window = gtk_window_new (GTK_WINDOW_POPUP);
433   gtk_window_set_resizable (GTK_WINDOW (priv->popup_window), FALSE);
434   g_signal_connect (priv->popup_window, "key_press_event",
435                     G_CALLBACK (gtk_entry_completion_popup_key_press),
436                     completion);
437   g_signal_connect (priv->popup_window, "button_press_event",
438                     G_CALLBACK (gtk_entry_completion_popup_button_press),
439                     completion);
440
441   popup_frame = gtk_frame_new (NULL);
442   gtk_frame_set_shadow_type (GTK_FRAME (popup_frame),
443                              GTK_SHADOW_ETCHED_IN);
444   gtk_widget_show (popup_frame);
445   gtk_container_add (GTK_CONTAINER (priv->popup_window), popup_frame);
446   
447   priv->vbox = gtk_vbox_new (FALSE, 0);
448   gtk_container_add (GTK_CONTAINER (popup_frame), priv->vbox);
449
450   gtk_container_add (GTK_CONTAINER (priv->scrolled_window), priv->tree_view);
451   gtk_box_pack_start (GTK_BOX (priv->vbox), priv->scrolled_window,
452                       TRUE, TRUE, 0);
453
454   /* we don't want to see the action treeview when no actions have
455    * been inserted, so we pack the action treeview after the first
456    * action has been added
457    */
458 }
459
460 static void
461 gtk_entry_completion_set_property (GObject      *object,
462                                    guint         prop_id,
463                                    const GValue *value,
464                                    GParamSpec   *pspec)
465 {
466   GtkEntryCompletion *completion = GTK_ENTRY_COMPLETION (object);
467   GtkEntryCompletionPrivate *priv = GTK_ENTRY_COMPLETION_GET_PRIVATE (completion);
468
469   switch (prop_id)
470     {
471       case PROP_MODEL:
472         gtk_entry_completion_set_model (completion,
473                                         g_value_get_object (value));
474         break;
475
476       case PROP_MINIMUM_KEY_LENGTH:
477         gtk_entry_completion_set_minimum_key_length (completion,
478                                                      g_value_get_int (value));
479         break;
480
481       case PROP_TEXT_COLUMN:
482         priv->text_column = g_value_get_int (value);
483         break;
484
485       case PROP_INLINE_COMPLETION:
486         priv->inline_completion = g_value_get_boolean (value);
487         break;
488
489       case PROP_POPUP_COMPLETION:
490         priv->popup_completion = g_value_get_boolean (value);
491         break;
492
493       default:
494         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
495         break;
496     }
497 }
498
499 static void
500 gtk_entry_completion_get_property (GObject    *object,
501                                    guint       prop_id,
502                                    GValue     *value,
503                                    GParamSpec *pspec)
504 {
505   GtkEntryCompletion *completion = GTK_ENTRY_COMPLETION (object);
506
507   switch (prop_id)
508     {
509       case PROP_MODEL:
510         g_value_set_object (value,
511                             gtk_entry_completion_get_model (completion));
512         break;
513
514       case PROP_MINIMUM_KEY_LENGTH:
515         g_value_set_int (value, gtk_entry_completion_get_minimum_key_length (completion));
516         break;
517
518       case PROP_TEXT_COLUMN:
519         g_value_set_int (value, gtk_entry_completion_get_text_column (completion));
520         break;
521
522       case PROP_INLINE_COMPLETION:
523         g_value_set_boolean (value, gtk_entry_completion_get_inline_completion (completion));
524         break;
525
526       case PROP_POPUP_COMPLETION:
527         g_value_set_boolean (value, gtk_entry_completion_get_popup_completion (completion));
528         break;
529
530       default:
531         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
532         break;
533     }
534 }
535
536 static void
537 gtk_entry_completion_finalize (GObject *object)
538 {
539   GtkEntryCompletion *completion = GTK_ENTRY_COMPLETION (object);
540
541   if (completion->priv->tree_view)
542     gtk_widget_destroy (completion->priv->tree_view);
543
544   if (completion->priv->entry)
545     gtk_entry_set_completion (GTK_ENTRY (completion->priv->entry), NULL);
546
547   if (completion->priv->actions)
548     g_object_unref (completion->priv->actions);
549
550   if (completion->priv->case_normalized_key)
551     g_free (completion->priv->case_normalized_key);
552
553   if (completion->priv->popup_window)
554     gtk_widget_destroy (completion->priv->popup_window);
555
556   G_OBJECT_CLASS (parent_class)->finalize (object);
557 }
558
559 /* implement cell layout interface */
560 static void
561 gtk_entry_completion_pack_start (GtkCellLayout   *cell_layout,
562                                  GtkCellRenderer *cell,
563                                  gboolean         expand)
564 {
565   GtkEntryCompletionPrivate *priv;
566
567   g_return_if_fail (GTK_IS_ENTRY_COMPLETION (cell_layout));
568
569   priv = GTK_ENTRY_COMPLETION_GET_PRIVATE (cell_layout);
570
571   gtk_tree_view_column_pack_start (priv->column, cell, expand);
572 }
573
574 static void
575 gtk_entry_completion_pack_end (GtkCellLayout   *cell_layout,
576                                GtkCellRenderer *cell,
577                                gboolean         expand)
578 {
579   GtkEntryCompletionPrivate *priv;
580
581   g_return_if_fail (GTK_IS_ENTRY_COMPLETION (cell_layout));
582
583   priv = GTK_ENTRY_COMPLETION_GET_PRIVATE (cell_layout);
584
585   gtk_tree_view_column_pack_end (priv->column, cell, expand);
586 }
587
588 static void
589 gtk_entry_completion_clear (GtkCellLayout *cell_layout)
590 {
591   GtkEntryCompletionPrivate *priv;
592
593   g_return_if_fail (GTK_IS_ENTRY_COMPLETION (cell_layout));
594
595   priv = GTK_ENTRY_COMPLETION_GET_PRIVATE (cell_layout);
596
597   gtk_tree_view_column_clear (priv->column);
598 }
599
600 static void
601 gtk_entry_completion_add_attribute (GtkCellLayout   *cell_layout,
602                                     GtkCellRenderer *cell,
603                                     const gchar     *attribute,
604                                     gint             column)
605 {
606   GtkEntryCompletionPrivate *priv;
607
608   g_return_if_fail (GTK_IS_ENTRY_COMPLETION (cell_layout));
609
610   priv = GTK_ENTRY_COMPLETION_GET_PRIVATE (cell_layout);
611
612   gtk_tree_view_column_add_attribute (priv->column, cell, attribute, column);
613 }
614
615 static void
616 gtk_entry_completion_set_cell_data_func (GtkCellLayout          *cell_layout,
617                                          GtkCellRenderer        *cell,
618                                          GtkCellLayoutDataFunc   func,
619                                          gpointer                func_data,
620                                          GDestroyNotify          destroy)
621 {
622   GtkEntryCompletionPrivate *priv;
623
624   g_return_if_fail (GTK_IS_ENTRY_COMPLETION (cell_layout));
625
626   priv = GTK_ENTRY_COMPLETION_GET_PRIVATE (cell_layout);
627
628   gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (priv->column),
629                                       cell, func, func_data, destroy);
630 }
631
632 static void
633 gtk_entry_completion_clear_attributes (GtkCellLayout   *cell_layout,
634                                        GtkCellRenderer *cell)
635 {
636   GtkEntryCompletionPrivate *priv;
637
638   g_return_if_fail (GTK_IS_ENTRY_COMPLETION (cell_layout));
639
640   priv = GTK_ENTRY_COMPLETION_GET_PRIVATE (cell_layout);
641
642   gtk_tree_view_column_clear_attributes (priv->column, cell);
643 }
644
645 static void
646 gtk_entry_completion_reorder (GtkCellLayout   *cell_layout,
647                               GtkCellRenderer *cell,
648                               gint             position)
649 {
650   GtkEntryCompletionPrivate *priv;
651
652   g_return_if_fail (GTK_IS_ENTRY_COMPLETION (cell_layout));
653
654   priv = GTK_ENTRY_COMPLETION_GET_PRIVATE (cell_layout);
655
656   gtk_cell_layout_reorder (GTK_CELL_LAYOUT (priv->column), cell, position);
657 }
658
659 /* all those callbacks */
660 static gboolean
661 gtk_entry_completion_default_completion_func (GtkEntryCompletion *completion,
662                                               const gchar        *key,
663                                               GtkTreeIter        *iter,
664                                               gpointer            user_data)
665 {
666   gchar *item = NULL;
667   gchar *normalized_string;
668   gchar *case_normalized_string;
669
670   gboolean ret = FALSE;
671
672   GtkTreeModel *model;
673
674   model = gtk_tree_model_filter_get_model (completion->priv->filter_model);
675
676   g_return_val_if_fail (gtk_tree_model_get_column_type (model, completion->priv->text_column) == G_TYPE_STRING, 
677                         FALSE);
678
679   gtk_tree_model_get (model, iter,
680                       completion->priv->text_column, &item,
681                       -1);
682
683   if (item != NULL)
684     {
685       normalized_string = g_utf8_normalize (item, -1, G_NORMALIZE_ALL);
686       case_normalized_string = g_utf8_casefold (normalized_string, -1);
687       
688       if (!strncmp (key, case_normalized_string, strlen (key)))
689         ret = TRUE;
690       
691       g_free (item);
692       g_free (normalized_string);
693       g_free (case_normalized_string);
694     }
695
696   return ret;
697 }
698
699 static gboolean
700 gtk_entry_completion_visible_func (GtkTreeModel *model,
701                                    GtkTreeIter  *iter,
702                                    gpointer      data)
703 {
704   gboolean ret = FALSE;
705
706   GtkEntryCompletion *completion = GTK_ENTRY_COMPLETION (data);
707
708   if (!completion->priv->case_normalized_key)
709     return ret;
710
711   if (completion->priv->match_func)
712     ret = (* completion->priv->match_func) (completion,
713                                             completion->priv->case_normalized_key,
714                                             iter,
715                                             completion->priv->match_data);
716   else if (completion->priv->text_column >= 0)
717     ret = gtk_entry_completion_default_completion_func (completion,
718                                                         completion->priv->case_normalized_key,
719                                                         iter,
720                                                         NULL);
721
722   return ret;
723 }
724
725 static gboolean
726 gtk_entry_completion_popup_key_press (GtkWidget   *widget,
727                                       GdkEventKey *event,
728                                       gpointer     user_data)
729 {
730   GtkEntryCompletion *completion = GTK_ENTRY_COMPLETION (user_data);
731
732   if (!GTK_WIDGET_MAPPED (completion->priv->popup_window))
733     return FALSE;
734
735   /* propagate event to the entry */
736   gtk_widget_event (completion->priv->entry, (GdkEvent *)event);
737
738   return TRUE;
739 }
740
741 static gboolean
742 gtk_entry_completion_popup_button_press (GtkWidget      *widget,
743                                          GdkEventButton *event,
744                                          gpointer        user_data)
745 {
746   GtkEntryCompletion *completion = GTK_ENTRY_COMPLETION (user_data);
747
748   if (!GTK_WIDGET_MAPPED (completion->priv->popup_window))
749     return FALSE;
750
751   /* if we come here, it's usually time to popdown */
752   _gtk_entry_completion_popdown (completion);
753
754   return TRUE;
755 }
756
757 static gboolean
758 gtk_entry_completion_list_button_press (GtkWidget      *widget,
759                                         GdkEventButton *event,
760                                         gpointer        user_data)
761 {
762   GtkEntryCompletion *completion = GTK_ENTRY_COMPLETION (user_data);
763   GtkTreePath *path = NULL;
764
765   if (!GTK_WIDGET_MAPPED (completion->priv->popup_window))
766     return FALSE;
767
768   if (gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (widget),
769                                      event->x, event->y,
770                                      &path, NULL, NULL, NULL))
771     {
772       GtkTreeIter iter;
773       gboolean entry_set;
774
775       gtk_tree_model_get_iter (GTK_TREE_MODEL (completion->priv->filter_model),
776                                &iter, path);
777       gtk_tree_path_free (path);
778
779       g_signal_handler_block (completion->priv->entry,
780                               completion->priv->changed_id);
781       g_signal_emit (completion, entry_completion_signals[MATCH_SELECTED],
782                      0, GTK_TREE_MODEL (completion->priv->filter_model),
783                      &iter, &entry_set);
784       g_signal_handler_unblock (completion->priv->entry,
785                                 completion->priv->changed_id);
786
787       _gtk_entry_completion_popdown (completion);
788
789       return TRUE;
790     }
791
792   return FALSE;
793 }
794
795 static gboolean
796 gtk_entry_completion_action_button_press (GtkWidget      *widget,
797                                           GdkEventButton *event,
798                                           gpointer        user_data)
799 {
800   GtkEntryCompletion *completion = GTK_ENTRY_COMPLETION (user_data);
801   GtkTreePath *path = NULL;
802
803   if (!GTK_WIDGET_MAPPED (completion->priv->popup_window))
804     return FALSE;
805
806   if (gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (widget),
807                                      event->x, event->y,
808                                      &path, NULL, NULL, NULL))
809     {
810       g_signal_emit (completion, entry_completion_signals[ACTION_ACTIVATED],
811                      0, gtk_tree_path_get_indices (path)[0]);
812       gtk_tree_path_free (path);
813
814       _gtk_entry_completion_popdown (completion);
815       return TRUE;
816     }
817
818   return FALSE;
819 }
820
821 static void
822 gtk_entry_completion_action_data_func (GtkTreeViewColumn *tree_column,
823                                        GtkCellRenderer   *cell,
824                                        GtkTreeModel      *model,
825                                        GtkTreeIter       *iter,
826                                        gpointer           data)
827 {
828   gchar *string = NULL;
829   gboolean markup;
830
831   gtk_tree_model_get (model, iter,
832                       0, &string,
833                       1, &markup,
834                       -1);
835
836   if (!string)
837     return;
838
839   if (markup)
840     g_object_set (cell,
841                   "text", NULL,
842                   "markup", string,
843                   NULL);
844   else
845     g_object_set (cell,
846                   "markup", NULL,
847                   "text", string,
848                   NULL);
849
850   g_free (string);
851 }
852
853 static void
854 gtk_entry_completion_selection_changed (GtkTreeSelection *selection,
855                                         gpointer          data)
856 {
857   GtkEntryCompletion *completion = GTK_ENTRY_COMPLETION (data);
858
859   if (completion->priv->first_sel_changed)
860     {
861       completion->priv->first_sel_changed = FALSE;
862       if (gtk_widget_is_focus (completion->priv->tree_view))
863         gtk_tree_selection_unselect_all (selection);
864     }
865 }
866
867 /* public API */
868
869 /**
870  * gtk_entry_completion_new:
871  *
872  * Creates a new #GtkEntryCompletion object.
873  *
874  * Return value: A newly created #GtkEntryCompletion object.
875  *
876  * Since: 2.4
877  */
878 GtkEntryCompletion *
879 gtk_entry_completion_new (void)
880 {
881   GtkEntryCompletion *completion;
882
883   completion = g_object_new (GTK_TYPE_ENTRY_COMPLETION, NULL);
884
885   return completion;
886 }
887
888 /**
889  * gtk_entry_completion_get_entry:
890  * @completion: A #GtkEntryCompletion.
891  *
892  * Gets the entry @completion has been attached to.
893  *
894  * Return value: The entry @completion has been attached to.
895  *
896  * Since: 2.4
897  */
898 GtkWidget *
899 gtk_entry_completion_get_entry (GtkEntryCompletion *completion)
900 {
901   g_return_val_if_fail (GTK_IS_ENTRY_COMPLETION (completion), NULL);
902
903   return completion->priv->entry;
904 }
905
906 /**
907  * gtk_entry_completion_set_model:
908  * @completion: A #GtkEntryCompletion.
909  * @model: The #GtkTreeModel.
910  *
911  * Sets the model for a #GtkEntryCompletion. If @completion already has
912  * a model set, it will remove it before setting the new model.
913  * If model is %NULL, then it will unset the model.
914  *
915  * Since: 2.4
916  */
917 void
918 gtk_entry_completion_set_model (GtkEntryCompletion *completion,
919                                 GtkTreeModel       *model)
920 {
921   g_return_if_fail (GTK_IS_ENTRY_COMPLETION (completion));
922   g_return_if_fail (model == NULL || GTK_IS_TREE_MODEL (model));
923
924   if (!model)
925     {
926       gtk_tree_view_set_model (GTK_TREE_VIEW (completion->priv->tree_view),
927                                NULL);
928       _gtk_entry_completion_popdown (completion);
929       completion->priv->filter_model = NULL;
930       return;
931     }
932      
933   /* code will unref the old filter model (if any) */
934   completion->priv->filter_model =
935     GTK_TREE_MODEL_FILTER (gtk_tree_model_filter_new (model, NULL));
936   gtk_tree_model_filter_set_visible_func (completion->priv->filter_model,
937                                           gtk_entry_completion_visible_func,
938                                           completion,
939                                           NULL);
940
941   gtk_tree_view_set_model (GTK_TREE_VIEW (completion->priv->tree_view),
942                            GTK_TREE_MODEL (completion->priv->filter_model));
943   g_object_unref (completion->priv->filter_model);
944
945   if (GTK_WIDGET_VISIBLE (completion->priv->popup_window))
946     _gtk_entry_completion_resize_popup (completion);
947 }
948
949 /**
950  * gtk_entry_completion_get_model:
951  * @completion: A #GtkEntryCompletion.
952  *
953  * Returns the model the #GtkEntryCompletion is using as data source.
954  * Returns %NULL if the model is unset.
955  *
956  * Return value: A #GtkTreeModel, or %NULL if none is currently being used.
957  *
958  * Since: 2.4
959  */
960 GtkTreeModel *
961 gtk_entry_completion_get_model (GtkEntryCompletion *completion)
962 {
963   g_return_val_if_fail (GTK_IS_ENTRY_COMPLETION (completion), NULL);
964
965   if (!completion->priv->filter_model)
966     return NULL;
967   
968   return gtk_tree_model_filter_get_model (completion->priv->filter_model);
969 }
970
971 /**
972  * gtk_entry_completion_set_match_func:
973  * @completion: A #GtkEntryCompletion.
974  * @func: The #GtkEntryCompletionMatchFunc to use.
975  * @func_data: The user data for @func.
976  * @func_notify: Destroy notifier for @func_data.
977  *
978  * Sets the match function for @completion to be @func. The match function
979  * is used to determine if a row should or should not be in the completion
980  * list.
981  *
982  * Since: 2.4.
983  */
984 void
985 gtk_entry_completion_set_match_func (GtkEntryCompletion          *completion,
986                                      GtkEntryCompletionMatchFunc  func,
987                                      gpointer                     func_data,
988                                      GDestroyNotify               func_notify)
989 {
990   g_return_if_fail (GTK_IS_ENTRY_COMPLETION (completion));
991
992   if (completion->priv->match_notify)
993     (* completion->priv->match_notify) (completion->priv->match_data);
994
995   completion->priv->match_func = func;
996   completion->priv->match_data = func_data;
997   completion->priv->match_notify = func_notify;
998 }
999
1000 /**
1001  * gtk_entry_completion_set_minimum_key_length:
1002  * @completion: A #GtkEntryCompletion.
1003  * @length: The minimum length of the key in order to start completing.
1004  *
1005  * Requires the length of the search key for @completion to be at least
1006  * @length. This is useful for long lists, where completing using a small
1007  * key takes a lot of time and will come up with meaningless results anyway
1008  * (ie, a too large dataset).
1009  *
1010  * Since: 2.4
1011  */
1012 void
1013 gtk_entry_completion_set_minimum_key_length (GtkEntryCompletion *completion,
1014                                              gint                length)
1015 {
1016   g_return_if_fail (GTK_IS_ENTRY_COMPLETION (completion));
1017   g_return_if_fail (length >= 1);
1018
1019   completion->priv->minimum_key_length = length;
1020 }
1021
1022 /**
1023  * gtk_entry_completion_get_minimum_key_length:
1024  * @completion: A #GtkEntryCompletion.
1025  *
1026  * Returns the minimum key length as set for @completion.
1027  *
1028  * Return value: The currently used minimum key length.
1029  *
1030  * Since: 2.4
1031  */
1032 gint
1033 gtk_entry_completion_get_minimum_key_length (GtkEntryCompletion *completion)
1034 {
1035   g_return_val_if_fail (GTK_IS_ENTRY_COMPLETION (completion), 0);
1036
1037   return completion->priv->minimum_key_length;
1038 }
1039
1040 /**
1041  * gtk_entry_completion_complete:
1042  * @completion: A #GtkEntryCompletion.
1043  *
1044  * Requests a completion operation, or in other words a refiltering of the
1045  * current list with completions, using the current key. The completion list
1046  * view will be updated accordingly.
1047  *
1048  * Since: 2.4
1049  */
1050 void
1051 gtk_entry_completion_complete (GtkEntryCompletion *completion)
1052 {
1053   gchar *tmp;
1054
1055   g_return_if_fail (GTK_IS_ENTRY_COMPLETION (completion));
1056
1057   if (!completion->priv->filter_model)
1058     return;
1059   
1060   if (completion->priv->case_normalized_key)
1061     g_free (completion->priv->case_normalized_key);
1062
1063   tmp = g_utf8_normalize (gtk_entry_get_text (GTK_ENTRY (completion->priv->entry)),
1064                           -1, G_NORMALIZE_ALL);
1065   completion->priv->case_normalized_key = g_utf8_casefold (tmp, -1);
1066   g_free (tmp);
1067
1068   gtk_tree_model_filter_refilter (completion->priv->filter_model);
1069 }
1070
1071 static void
1072 gtk_entry_completion_insert_action (GtkEntryCompletion *completion,
1073                                     gint                index,
1074                                     const gchar        *string,
1075                                     gboolean            markup)
1076 {
1077   GtkTreeIter iter;
1078
1079   gtk_list_store_insert (completion->priv->actions, &iter, index);
1080   gtk_list_store_set (completion->priv->actions, &iter,
1081                       0, string,
1082                       1, markup,
1083                       -1);
1084
1085   if (!completion->priv->action_view->parent)
1086     {
1087       GtkTreePath *path = gtk_tree_path_new_from_indices (0, -1);
1088
1089       gtk_tree_view_set_cursor (GTK_TREE_VIEW (completion->priv->action_view),
1090                                 path, NULL, FALSE);
1091       gtk_tree_path_free (path);
1092
1093       gtk_box_pack_start (GTK_BOX (completion->priv->vbox),
1094                           completion->priv->action_view, FALSE, FALSE, 0);
1095       gtk_widget_show (completion->priv->action_view);
1096     }
1097 }
1098
1099 /**
1100  * gtk_entry_completion_insert_action_text:
1101  * @completion: A #GtkEntryCompletion.
1102  * @index_: The index of the item to insert.
1103  * @text: Text of the item to insert.
1104  *
1105  * Inserts an action in @completion's action item list at position @index_
1106  * with text @text. If you want the action item to have markup, use
1107  * gtk_entry_completion_insert_action_markup().
1108  *
1109  * Since: 2.4
1110  */
1111 void
1112 gtk_entry_completion_insert_action_text (GtkEntryCompletion *completion,
1113                                          gint                index_,
1114                                          const gchar        *text)
1115 {
1116   g_return_if_fail (GTK_IS_ENTRY_COMPLETION (completion));
1117   g_return_if_fail (text != NULL);
1118
1119   gtk_entry_completion_insert_action (completion, index_, text, FALSE);
1120 }
1121
1122 /**
1123  * gtk_entry_completion_insert_action_markup:
1124  * @completion: A #GtkEntryCompletion.
1125  * @index_: The index of the item to insert.
1126  * @markup: Markup of the item to insert.
1127  *
1128  * Inserts an action in @completion's action item list at position @index_
1129  * with markup @markup.
1130  *
1131  * Since: 2.4
1132  */
1133 void
1134 gtk_entry_completion_insert_action_markup (GtkEntryCompletion *completion,
1135                                            gint                index_,
1136                                            const gchar        *markup)
1137 {
1138   g_return_if_fail (GTK_IS_ENTRY_COMPLETION (completion));
1139   g_return_if_fail (markup != NULL);
1140
1141   gtk_entry_completion_insert_action (completion, index_, markup, TRUE);
1142 }
1143
1144 /**
1145  * gtk_entry_completion_delete_action:
1146  * @completion: A #GtkEntryCompletion.
1147  * @index_: The index of the item to Delete.
1148  *
1149  * Deletes the action at @index_ from @completion's action list.
1150  *
1151  * Since: 2.4
1152  */
1153 void
1154 gtk_entry_completion_delete_action (GtkEntryCompletion *completion,
1155                                     gint                index_)
1156 {
1157   GtkTreeIter iter;
1158
1159   g_return_if_fail (GTK_IS_ENTRY_COMPLETION (completion));
1160   g_return_if_fail (index_ >= 0);
1161
1162   gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (completion->priv->actions),
1163                                  &iter, NULL, index_);
1164   gtk_list_store_remove (completion->priv->actions, &iter);
1165 }
1166
1167 /**
1168  * gtk_entry_completion_set_text_column:
1169  * @completion: A #GtkEntryCompletion.
1170  * @column: The column in the model of @completion to get strings from.
1171  *
1172  * Convenience function for setting up the most used case of this code: a
1173  * completion list with just strings. This function will set up @completion
1174  * to have a list displaying all (and just) strings in the completion list,
1175  * and to get those strings from @column in the model of @completion.
1176  *
1177  * This functions creates and adds a #GtkCellRendererText for the selected 
1178  * column. If you need to set the text column, but don't want the cell 
1179  * renderer, use g_object_set() to set the ::text_column property directly.
1180  * 
1181  * Since: 2.4
1182  */
1183 void
1184 gtk_entry_completion_set_text_column (GtkEntryCompletion *completion,
1185                                       gint                column)
1186 {
1187   GtkCellRenderer *cell;
1188
1189   g_return_if_fail (GTK_IS_ENTRY_COMPLETION (completion));
1190   g_return_if_fail (column >= 0);
1191
1192   completion->priv->text_column = column;
1193
1194   cell = gtk_cell_renderer_text_new ();
1195   gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (completion),
1196                               cell, TRUE);
1197   gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (completion),
1198                                  cell,
1199                                  "text", column);
1200
1201   g_object_notify (G_OBJECT (completion), "text_column");
1202 }
1203
1204 /**
1205  * gtk_entry_completion_get_text_column:
1206  * @completion: a #GtkEntryCompletion
1207  * 
1208  * Returns the column in the model of @completion to get strings from.
1209  * 
1210  * Return value: the column containing the strings
1211  *
1212  * Since: 2.6
1213  **/
1214 gint
1215 gtk_entry_completion_get_text_column (GtkEntryCompletion *completion)
1216 {
1217   g_return_val_if_fail (GTK_IS_ENTRY_COMPLETION (completion), -1);
1218
1219   return completion->priv->text_column;  
1220 }
1221
1222 /* private */
1223
1224 static gboolean
1225 gtk_entry_completion_list_enter_notify (GtkWidget        *widget,
1226                                         GdkEventCrossing *event,
1227                                         gpointer          data)
1228 {
1229   GtkEntryCompletion *completion = GTK_ENTRY_COMPLETION (data);
1230   
1231   return completion->priv->ignore_enter;
1232 }
1233
1234 static gboolean
1235 gtk_entry_completion_list_motion_notify (GtkWidget      *widget,
1236                                          GdkEventMotion *event,
1237                                          gpointer        data)
1238 {
1239   GtkEntryCompletion *completion = GTK_ENTRY_COMPLETION (data);
1240
1241   completion->priv->ignore_enter = FALSE; 
1242   
1243   return FALSE;
1244 }
1245
1246
1247 /* some nasty size requisition */
1248 gboolean
1249 _gtk_entry_completion_resize_popup (GtkEntryCompletion *completion)
1250 {
1251   gint x, y;
1252   gint matches, items, height, x_border, y_border;
1253   GdkScreen *screen;
1254   gint monitor_num;
1255   GdkRectangle monitor;
1256   GtkRequisition popup_req;
1257   GtkRequisition entry_req;
1258   GtkTreePath *path;
1259   gboolean above;
1260   gint width;
1261
1262   if (!completion->priv->entry->window)
1263     return FALSE;
1264
1265   gdk_window_get_origin (completion->priv->entry->window, &x, &y);
1266   _gtk_entry_get_borders (GTK_ENTRY (completion->priv->entry), &x_border, &y_border);
1267
1268   matches = gtk_tree_model_iter_n_children (GTK_TREE_MODEL (completion->priv->filter_model), NULL);
1269
1270   items = MIN (matches, 15);
1271
1272   gtk_tree_view_column_cell_get_size (completion->priv->column, NULL,
1273                                       NULL, NULL, NULL, &height);
1274
1275   if (items <= 0)
1276     gtk_widget_hide (completion->priv->scrolled_window);
1277   else
1278     gtk_widget_show (completion->priv->scrolled_window);
1279
1280   screen = gtk_widget_get_screen (GTK_WIDGET (completion->priv->entry));
1281   monitor_num = gdk_screen_get_monitor_at_window (screen, 
1282                                                   GTK_WIDGET (completion->priv->entry)->window);
1283   gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor);
1284
1285   width = MIN (completion->priv->entry->allocation.width, monitor.width) - 2 * x_border;
1286   gtk_widget_set_size_request (completion->priv->tree_view, width, items * height);
1287
1288   /* default on no match */
1289   completion->priv->current_selected = -1;
1290
1291   items = gtk_tree_model_iter_n_children (GTK_TREE_MODEL (completion->priv->actions), NULL);
1292
1293   if (items)
1294     {
1295       gtk_widget_show (completion->priv->action_view);
1296       gtk_widget_set_size_request (completion->priv->action_view, width, -1);
1297     }
1298   else
1299     gtk_widget_hide (completion->priv->action_view);
1300
1301   gtk_widget_size_request (completion->priv->popup_window, &popup_req);
1302   gtk_widget_size_request (completion->priv->entry, &entry_req);
1303   
1304   if (x < monitor.x)
1305     x = monitor.x;
1306   else if (x + popup_req.width > monitor.x + monitor.width)
1307     x = monitor.x + monitor.width - popup_req.width;
1308   
1309   if (y + entry_req.height + popup_req.height <= monitor.y + monitor.height)
1310     {
1311       y += entry_req.height;
1312       above = FALSE;
1313     }
1314   else
1315     {
1316       y -= popup_req.height;
1317       above = TRUE;
1318     }
1319   
1320   if (matches > 0) 
1321     {
1322       path = gtk_tree_path_new_from_indices (above ? matches - 1 : 0, -1);
1323       gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (completion->priv->tree_view), path, 
1324                                     NULL, FALSE, 0.0, 0.0);
1325       gtk_tree_path_free (path);
1326     }
1327
1328   gtk_window_move (GTK_WINDOW (completion->priv->popup_window), x, y);
1329
1330   return above;
1331 }
1332
1333 void
1334 _gtk_entry_completion_popup (GtkEntryCompletion *completion)
1335 {
1336   GtkTreeViewColumn *column;
1337   GList *renderers;
1338
1339   if (GTK_WIDGET_MAPPED (completion->priv->popup_window))
1340     return;
1341
1342   if (!GTK_WIDGET_MAPPED (completion->priv->entry))
1343     return;
1344
1345   completion->priv->ignore_enter = TRUE;
1346     
1347   column = gtk_tree_view_get_column (GTK_TREE_VIEW (completion->priv->action_view), 0);
1348   renderers = gtk_tree_view_column_get_cell_renderers (column);
1349   gtk_widget_ensure_style (completion->priv->tree_view);
1350   g_object_set (GTK_CELL_RENDERER (renderers->data), "cell_background_gdk",
1351                 &completion->priv->tree_view->style->bg[GTK_STATE_NORMAL],
1352                 NULL);
1353   g_list_free (renderers);
1354
1355   gtk_widget_show_all (completion->priv->vbox);
1356
1357   _gtk_entry_completion_resize_popup (completion);
1358
1359   gtk_widget_show (completion->priv->popup_window);
1360     
1361   gtk_grab_add (completion->priv->popup_window);
1362   gdk_pointer_grab (completion->priv->popup_window->window, TRUE,
1363                     GDK_BUTTON_PRESS_MASK |
1364                     GDK_BUTTON_RELEASE_MASK |
1365                     GDK_POINTER_MOTION_MASK,
1366                     NULL, NULL, GDK_CURRENT_TIME);
1367 }
1368
1369 void
1370 _gtk_entry_completion_popdown (GtkEntryCompletion *completion)
1371 {
1372   if (!GTK_WIDGET_MAPPED (completion->priv->popup_window))
1373     return;
1374
1375   completion->priv->ignore_enter = FALSE;
1376   
1377   gdk_pointer_ungrab (GDK_CURRENT_TIME);
1378   gtk_grab_remove (completion->priv->popup_window);
1379
1380   gtk_widget_hide (completion->priv->popup_window);
1381 }
1382
1383 static gboolean 
1384 gtk_entry_completion_match_selected (GtkEntryCompletion *completion,
1385                                      GtkTreeModel       *model,
1386                                      GtkTreeIter        *iter)
1387 {
1388   gchar *str = NULL;
1389
1390   gtk_tree_model_get (model, iter, completion->priv->text_column, &str, -1);
1391   gtk_entry_set_text (GTK_ENTRY (completion->priv->entry), str);
1392   
1393   /* move cursor to the end */
1394   gtk_editable_set_position (GTK_EDITABLE (completion->priv->entry), -1);
1395   
1396   g_free (str);
1397
1398   return TRUE;
1399 }
1400
1401
1402 static gchar *
1403 gtk_entry_completion_compute_prefix (GtkEntryCompletion *completion)
1404 {
1405   GtkTreeIter iter;
1406   gchar *prefix = NULL;
1407   gboolean valid;
1408
1409   const gchar *key = gtk_entry_get_text (GTK_ENTRY (completion->priv->entry));
1410
1411   valid = gtk_tree_model_get_iter_first (GTK_TREE_MODEL (completion->priv->filter_model),
1412                                          &iter);
1413   
1414   while (valid)
1415     {
1416       gchar *text;
1417       
1418       gtk_tree_model_get (GTK_TREE_MODEL (completion->priv->filter_model),
1419                           &iter, completion->priv->text_column, &text,
1420                           -1);
1421
1422       if (g_str_has_prefix (text, key))
1423         {
1424           if (!prefix)
1425             prefix = g_strdup (text);
1426           else
1427             {
1428               gchar *p = prefix;
1429               const gchar *q = text;
1430               
1431               while (*p && *p == *q)
1432                 {
1433                   p++;
1434                   q++;
1435                 }
1436               
1437               *p = '\0';
1438             }
1439         }
1440       
1441       g_free (text);
1442       valid = gtk_tree_model_iter_next (GTK_TREE_MODEL (completion->priv->filter_model),
1443                                         &iter);
1444     }
1445
1446   return prefix;
1447 }
1448
1449
1450 static gboolean
1451 gtk_entry_completion_real_insert_prefix (GtkEntryCompletion *completion,
1452                                          const gchar        *prefix)
1453 {
1454   if (prefix)
1455     {
1456       gint key_len;
1457       gint prefix_len;
1458       gint pos;
1459       const gchar *key;
1460
1461       prefix_len = g_utf8_strlen (prefix, -1);
1462
1463       key = gtk_entry_get_text (GTK_ENTRY (completion->priv->entry));
1464       key_len = g_utf8_strlen (key, -1);
1465
1466       if (prefix_len > key_len)
1467         {
1468           gtk_editable_insert_text (GTK_EDITABLE (completion->priv->entry),
1469                                     prefix + key_len, -1, &pos);
1470           gtk_editable_select_region (GTK_EDITABLE (completion->priv->entry),
1471                                       key_len, prefix_len);
1472
1473           completion->priv->has_completion = TRUE;
1474         }
1475     }
1476
1477   return TRUE;
1478 }
1479
1480 /**
1481  * gtk_entry_completion_insert_prefix:
1482  * @completion: a #GtkEntryCompletion
1483  * 
1484  * Requests a prefix insertion. 
1485  * 
1486  * Since: 2.6
1487  **/
1488 void
1489 gtk_entry_completion_insert_prefix (GtkEntryCompletion *completion)
1490 {
1491   gboolean done;
1492   gchar *prefix;
1493
1494   g_signal_handler_block (completion->priv->entry,
1495                           completion->priv->insert_text_id);
1496   prefix = gtk_entry_completion_compute_prefix (completion);
1497   if (prefix)
1498     {
1499       g_signal_emit (completion, entry_completion_signals[INSERT_PREFIX],
1500                      0, prefix, &done);
1501       g_free (prefix);
1502     }
1503   g_signal_handler_unblock (completion->priv->entry,
1504                             completion->priv->insert_text_id);
1505 }
1506
1507 /**
1508  * gtk_entry_completion_set_inline_completion:
1509  * @completion: a #GtkEntryCompletion
1510  * @inline_completion: %TRUE to do inline completion
1511  * 
1512  * Sets whether the common prefix of the possible completions should
1513  * be automatically inserted in the entry.
1514  * 
1515  * Since: 2.6
1516  **/
1517 void 
1518 gtk_entry_completion_set_inline_completion (GtkEntryCompletion *completion,
1519                                             gboolean            inline_completion)
1520 {
1521   g_return_if_fail (GTK_IS_ENTRY_COMPLETION (completion));
1522   
1523   inline_completion = inline_completion != FALSE;
1524
1525   if (completion->priv->inline_completion != inline_completion)
1526     {
1527       completion->priv->inline_completion = inline_completion;
1528
1529       g_object_notify (G_OBJECT (completion), "inline_completion");
1530     }
1531 }
1532
1533
1534 /**
1535  * gtk_entry_completion_get_inline_completion:
1536  * @completion: a #GtkEntryCompletion
1537  * 
1538  * Returns whether the common prefix of the possible completions should
1539  * be automatically inserted in the entry.
1540  * 
1541  * Return value: %TRUE if inline completion is turned on
1542  * 
1543  * Since: 2.6
1544  **/
1545 gboolean
1546 gtk_entry_completion_get_inline_completion (GtkEntryCompletion *completion)
1547 {
1548   g_return_val_if_fail (GTK_IS_ENTRY_COMPLETION (completion), FALSE);
1549   
1550   return completion->priv->inline_completion;
1551 }
1552
1553 /**
1554  * gtk_entry_completion_set_popup_completion:
1555  * @completion: a #GtkEntryCompletion
1556  * @popup_completion: %TRUE to do popup completion
1557  * 
1558  * Sets whether the completions should be presented in a popup window.
1559  * 
1560  * Since: 2.6
1561  **/
1562 void 
1563 gtk_entry_completion_set_popup_completion (GtkEntryCompletion *completion,
1564                                            gboolean            popup_completion)
1565 {
1566   g_return_if_fail (GTK_IS_ENTRY_COMPLETION (completion));
1567   
1568   popup_completion = popup_completion != FALSE;
1569
1570   if (completion->priv->popup_completion != popup_completion)
1571     {
1572       completion->priv->popup_completion = popup_completion;
1573
1574       g_object_notify (G_OBJECT (completion), "popup_completion");
1575     }
1576 }
1577
1578
1579 /**
1580  * gtk_entry_completion_get_popup_completion:
1581  * @completion: a #GtkEntryCompletion
1582  * 
1583  * Returns whether the completions should be presented in a popup window.
1584  * 
1585  * Return value: %TRUE if popup completion is turned on
1586  * 
1587  * Since: 2.6
1588  **/
1589 gboolean
1590 gtk_entry_completion_get_popup_completion (GtkEntryCompletion *completion)
1591 {
1592   g_return_val_if_fail (GTK_IS_ENTRY_COMPLETION (completion), TRUE);
1593   
1594   return completion->priv->popup_completion;
1595 }