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