]> Pileus Git - ~andy/gtk/blob - gtk/gtkentrycompletion.c
gdk/linux-fb/gdkgc-fb.c gdk/win32/gdkgc-win32.c
[~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                                                           gchar              *key);
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 static void
907 filter_model_changed_cb (GtkTreeModel     *model,
908                          GtkTreePath      *path,
909                          GtkTreeIter      *iter,
910                          gpointer          user_data)
911 {
912   GtkEntryCompletion *completion = GTK_ENTRY_COMPLETION (user_data);
913
914   if (GTK_WIDGET_VISIBLE (completion->priv->popup_window))
915     _gtk_entry_completion_resize_popup (completion);  
916 }
917
918 /**
919  * gtk_entry_completion_set_model:
920  * @completion: A #GtkEntryCompletion.
921  * @model: The #GtkTreeModel.
922  *
923  * Sets the model for a #GtkEntryCompletion. If @completion already has
924  * a model set, it will remove it before setting the new model.
925  * If model is %NULL, then it will unset the model.
926  *
927  * Since: 2.4
928  */
929 void
930 gtk_entry_completion_set_model (GtkEntryCompletion *completion,
931                                 GtkTreeModel       *model)
932 {
933   g_return_if_fail (GTK_IS_ENTRY_COMPLETION (completion));
934   g_return_if_fail (model == NULL || GTK_IS_TREE_MODEL (model));
935
936   if (!model)
937     {
938       gtk_tree_view_set_model (GTK_TREE_VIEW (completion->priv->tree_view),
939                                NULL);
940       _gtk_entry_completion_popdown (completion);
941       completion->priv->filter_model = NULL;
942       return;
943     }
944      
945   /* code will unref the old filter model (if any) */
946   completion->priv->filter_model =
947     GTK_TREE_MODEL_FILTER (gtk_tree_model_filter_new (model, NULL));
948   gtk_tree_model_filter_set_visible_func (completion->priv->filter_model,
949                                           gtk_entry_completion_visible_func,
950                                           completion,
951                                           NULL);
952
953   gtk_tree_view_set_model (GTK_TREE_VIEW (completion->priv->tree_view),
954                            GTK_TREE_MODEL (completion->priv->filter_model));
955   g_object_unref (completion->priv->filter_model);
956
957   if (GTK_WIDGET_VISIBLE (completion->priv->popup_window))
958     _gtk_entry_completion_resize_popup (completion);
959 }
960
961 /**
962  * gtk_entry_completion_get_model:
963  * @completion: A #GtkEntryCompletion.
964  *
965  * Returns the model the #GtkEntryCompletion is using as data source.
966  * Returns %NULL if the model is unset.
967  *
968  * Return value: A #GtkTreeModel, or %NULL if none is currently being used.
969  *
970  * Since: 2.4
971  */
972 GtkTreeModel *
973 gtk_entry_completion_get_model (GtkEntryCompletion *completion)
974 {
975   g_return_val_if_fail (GTK_IS_ENTRY_COMPLETION (completion), NULL);
976
977   if (!completion->priv->filter_model)
978     return NULL;
979   
980   return gtk_tree_model_filter_get_model (completion->priv->filter_model);
981 }
982
983 /**
984  * gtk_entry_completion_set_match_func:
985  * @completion: A #GtkEntryCompletion.
986  * @func: The #GtkEntryCompletionMatchFunc to use.
987  * @func_data: The user data for @func.
988  * @func_notify: Destroy notifier for @func_data.
989  *
990  * Sets the match function for @completion to be @func. The match function
991  * is used to determine if a row should or should not be in the completion
992  * list.
993  *
994  * Since: 2.4.
995  */
996 void
997 gtk_entry_completion_set_match_func (GtkEntryCompletion          *completion,
998                                      GtkEntryCompletionMatchFunc  func,
999                                      gpointer                     func_data,
1000                                      GDestroyNotify               func_notify)
1001 {
1002   g_return_if_fail (GTK_IS_ENTRY_COMPLETION (completion));
1003
1004   if (completion->priv->match_notify)
1005     (* completion->priv->match_notify) (completion->priv->match_data);
1006
1007   completion->priv->match_func = func;
1008   completion->priv->match_data = func_data;
1009   completion->priv->match_notify = func_notify;
1010 }
1011
1012 /**
1013  * gtk_entry_completion_set_minimum_key_length:
1014  * @completion: A #GtkEntryCompletion.
1015  * @length: The minimum length of the key in order to start completing.
1016  *
1017  * Requires the length of the search key for @completion to be at least
1018  * @length. This is useful for long lists, where completing using a small
1019  * key takes a lot of time and will come up with meaningless results anyway
1020  * (ie, a too large dataset).
1021  *
1022  * Since: 2.4
1023  */
1024 void
1025 gtk_entry_completion_set_minimum_key_length (GtkEntryCompletion *completion,
1026                                              gint                length)
1027 {
1028   g_return_if_fail (GTK_IS_ENTRY_COMPLETION (completion));
1029   g_return_if_fail (length >= 1);
1030
1031   completion->priv->minimum_key_length = length;
1032 }
1033
1034 /**
1035  * gtk_entry_completion_get_minimum_key_length:
1036  * @completion: A #GtkEntryCompletion.
1037  *
1038  * Returns the minimum key length as set for @completion.
1039  *
1040  * Return value: The currently used minimum key length.
1041  *
1042  * Since: 2.4
1043  */
1044 gint
1045 gtk_entry_completion_get_minimum_key_length (GtkEntryCompletion *completion)
1046 {
1047   g_return_val_if_fail (GTK_IS_ENTRY_COMPLETION (completion), 0);
1048
1049   return completion->priv->minimum_key_length;
1050 }
1051
1052 /**
1053  * gtk_entry_completion_complete:
1054  * @completion: A #GtkEntryCompletion.
1055  *
1056  * Requests a completion operation, or in other words a refiltering of the
1057  * current list with completions, using the current key. The completion list
1058  * view will be updated accordingly.
1059  *
1060  * Since: 2.4
1061  */
1062 void
1063 gtk_entry_completion_complete (GtkEntryCompletion *completion)
1064 {
1065   gchar *tmp;
1066
1067   g_return_if_fail (GTK_IS_ENTRY_COMPLETION (completion));
1068
1069   if (!completion->priv->filter_model)
1070     return;
1071   
1072   if (completion->priv->case_normalized_key)
1073     g_free (completion->priv->case_normalized_key);
1074
1075   tmp = g_utf8_normalize (gtk_entry_get_text (GTK_ENTRY (completion->priv->entry)),
1076                           -1, G_NORMALIZE_ALL);
1077   completion->priv->case_normalized_key = g_utf8_casefold (tmp, -1);
1078   g_free (tmp);
1079
1080   gtk_tree_model_filter_refilter (completion->priv->filter_model);
1081 }
1082
1083 static void
1084 gtk_entry_completion_insert_action (GtkEntryCompletion *completion,
1085                                     gint                index,
1086                                     const gchar        *string,
1087                                     gboolean            markup)
1088 {
1089   GtkTreeIter iter;
1090
1091   gtk_list_store_insert (completion->priv->actions, &iter, index);
1092   gtk_list_store_set (completion->priv->actions, &iter,
1093                       0, string,
1094                       1, markup,
1095                       -1);
1096
1097   if (!completion->priv->action_view->parent)
1098     {
1099       GtkTreePath *path = gtk_tree_path_new_from_indices (0, -1);
1100
1101       gtk_tree_view_set_cursor (GTK_TREE_VIEW (completion->priv->action_view),
1102                                 path, NULL, FALSE);
1103       gtk_tree_path_free (path);
1104
1105       gtk_box_pack_start (GTK_BOX (completion->priv->vbox),
1106                           completion->priv->action_view, FALSE, FALSE, 0);
1107       gtk_widget_show (completion->priv->action_view);
1108     }
1109 }
1110
1111 /**
1112  * gtk_entry_completion_insert_action_text:
1113  * @completion: A #GtkEntryCompletion.
1114  * @index_: The index of the item to insert.
1115  * @text: Text of the item to insert.
1116  *
1117  * Inserts an action in @completion's action item list at position @index_
1118  * with text @text. If you want the action item to have markup, use
1119  * gtk_entry_completion_insert_action_markup().
1120  *
1121  * Since: 2.4
1122  */
1123 void
1124 gtk_entry_completion_insert_action_text (GtkEntryCompletion *completion,
1125                                          gint                index_,
1126                                          const gchar        *text)
1127 {
1128   g_return_if_fail (GTK_IS_ENTRY_COMPLETION (completion));
1129   g_return_if_fail (text != NULL);
1130
1131   gtk_entry_completion_insert_action (completion, index_, text, FALSE);
1132 }
1133
1134 /**
1135  * gtk_entry_completion_insert_action_markup:
1136  * @completion: A #GtkEntryCompletion.
1137  * @index_: The index of the item to insert.
1138  * @markup: Markup of the item to insert.
1139  *
1140  * Inserts an action in @completion's action item list at position @index_
1141  * with markup @markup.
1142  *
1143  * Since: 2.4
1144  */
1145 void
1146 gtk_entry_completion_insert_action_markup (GtkEntryCompletion *completion,
1147                                            gint                index_,
1148                                            const gchar        *markup)
1149 {
1150   g_return_if_fail (GTK_IS_ENTRY_COMPLETION (completion));
1151   g_return_if_fail (markup != NULL);
1152
1153   gtk_entry_completion_insert_action (completion, index_, markup, TRUE);
1154 }
1155
1156 /**
1157  * gtk_entry_completion_delete_action:
1158  * @completion: A #GtkEntryCompletion.
1159  * @index_: The index of the item to Delete.
1160  *
1161  * Deletes the action at @index_ from @completion's action list.
1162  *
1163  * Since: 2.4
1164  */
1165 void
1166 gtk_entry_completion_delete_action (GtkEntryCompletion *completion,
1167                                     gint                index_)
1168 {
1169   GtkTreeIter iter;
1170
1171   g_return_if_fail (GTK_IS_ENTRY_COMPLETION (completion));
1172   g_return_if_fail (index_ >= 0);
1173
1174   gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (completion->priv->actions),
1175                                  &iter, NULL, index_);
1176   gtk_list_store_remove (completion->priv->actions, &iter);
1177 }
1178
1179 /**
1180  * gtk_entry_completion_set_text_column:
1181  * @completion: A #GtkEntryCompletion.
1182  * @column: The column in the model of @completion to get strings from.
1183  *
1184  * Convenience function for setting up the most used case of this code: a
1185  * completion list with just strings. This function will set up @completion
1186  * to have a list displaying all (and just) strings in the completion list,
1187  * and to get those strings from @column in the model of @completion.
1188  *
1189  * This functions creates and adds a #GtkCellRendererText for the selected 
1190  * column. If you need to set the text column, but don't want the cell 
1191  * renderer, use g_object_set() to set the ::text_column property directly.
1192  * 
1193  * Since: 2.4
1194  */
1195 void
1196 gtk_entry_completion_set_text_column (GtkEntryCompletion *completion,
1197                                       gint                column)
1198 {
1199   GtkCellRenderer *cell;
1200
1201   g_return_if_fail (GTK_IS_ENTRY_COMPLETION (completion));
1202   g_return_if_fail (column >= 0);
1203
1204   completion->priv->text_column = column;
1205
1206   cell = gtk_cell_renderer_text_new ();
1207   gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (completion),
1208                               cell, TRUE);
1209   gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (completion),
1210                                  cell,
1211                                  "text", column);
1212
1213   g_object_notify (G_OBJECT (completion), "text_column");
1214 }
1215
1216 /**
1217  * gtk_entry_completion_get_text_column:
1218  * @completion: a #GtkEntryCompletion
1219  * 
1220  * Returns the column in the model of @completion to get strings from.
1221  * 
1222  * Return value: the column containing the strings
1223  *
1224  * Since: 2.6
1225  **/
1226 gint
1227 gtk_entry_completion_get_text_column (GtkEntryCompletion *completion)
1228 {
1229   g_return_val_if_fail (GTK_IS_ENTRY_COMPLETION (completion), -1);
1230
1231   return completion->priv->text_column;  
1232 }
1233
1234 /* private */
1235
1236 static gboolean
1237 gtk_entry_completion_list_enter_notify (GtkWidget        *widget,
1238                                         GdkEventCrossing *event,
1239                                         gpointer          data)
1240 {
1241   GtkEntryCompletion *completion = GTK_ENTRY_COMPLETION (data);
1242   
1243   return completion->priv->ignore_enter;
1244 }
1245
1246 static gboolean
1247 gtk_entry_completion_list_motion_notify (GtkWidget      *widget,
1248                                          GdkEventMotion *event,
1249                                          gpointer        data)
1250 {
1251   GtkEntryCompletion *completion = GTK_ENTRY_COMPLETION (data);
1252
1253   completion->priv->ignore_enter = FALSE; 
1254   
1255   return FALSE;
1256 }
1257
1258
1259 /* some nasty size requisition */
1260 gboolean
1261 _gtk_entry_completion_resize_popup (GtkEntryCompletion *completion)
1262 {
1263   gint x, y;
1264   gint matches, items, height, x_border, y_border;
1265   GdkScreen *screen;
1266   gint monitor_num;
1267   GdkRectangle monitor;
1268   GtkRequisition popup_req;
1269   GtkRequisition entry_req;
1270   GtkTreePath *path;
1271   gboolean above;
1272   gint width;
1273
1274   if (!completion->priv->entry->window)
1275     return FALSE;
1276
1277   gdk_window_get_origin (completion->priv->entry->window, &x, &y);
1278   _gtk_entry_get_borders (GTK_ENTRY (completion->priv->entry), &x_border, &y_border);
1279
1280   matches = gtk_tree_model_iter_n_children (GTK_TREE_MODEL (completion->priv->filter_model), NULL);
1281
1282   items = MIN (matches, 15);
1283
1284   gtk_tree_view_column_cell_get_size (completion->priv->column, NULL,
1285                                       NULL, NULL, NULL, &height);
1286
1287   if (items <= 0)
1288     gtk_widget_hide (completion->priv->scrolled_window);
1289   else
1290     gtk_widget_show (completion->priv->scrolled_window);
1291
1292   screen = gtk_widget_get_screen (GTK_WIDGET (completion->priv->entry));
1293   monitor_num = gdk_screen_get_monitor_at_window (screen, 
1294                                                   GTK_WIDGET (completion->priv->entry)->window);
1295   gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor);
1296
1297   width = MIN (completion->priv->entry->allocation.width, monitor.width) - 2 * x_border;
1298   gtk_widget_set_size_request (completion->priv->tree_view, width, items * height);
1299
1300   /* default on no match */
1301   completion->priv->current_selected = -1;
1302
1303   items = gtk_tree_model_iter_n_children (GTK_TREE_MODEL (completion->priv->actions), NULL);
1304
1305   if (items)
1306     {
1307       gtk_widget_show (completion->priv->action_view);
1308       gtk_widget_set_size_request (completion->priv->action_view, width, -1);
1309     }
1310   else
1311     gtk_widget_hide (completion->priv->action_view);
1312
1313   gtk_widget_size_request (completion->priv->popup_window, &popup_req);
1314   gtk_widget_size_request (completion->priv->entry, &entry_req);
1315   
1316   if (x < monitor.x)
1317     x = monitor.x;
1318   else if (x + popup_req.width > monitor.x + monitor.width)
1319     x = monitor.x + monitor.width - popup_req.width;
1320   
1321   if (y + entry_req.height + popup_req.height <= monitor.y + monitor.height)
1322     {
1323       y += entry_req.height;
1324       above = FALSE;
1325     }
1326   else
1327     {
1328       y -= popup_req.height;
1329       above = TRUE;
1330     }
1331   
1332   if (matches > 0) 
1333     {
1334       path = gtk_tree_path_new_from_indices (above ? matches - 1 : 0, -1);
1335       gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (completion->priv->tree_view), path, 
1336                                     NULL, FALSE, 0.0, 0.0);
1337       gtk_tree_path_free (path);
1338     }
1339
1340   gtk_window_move (GTK_WINDOW (completion->priv->popup_window), x, y);
1341
1342   return above;
1343 }
1344
1345 void
1346 _gtk_entry_completion_popup (GtkEntryCompletion *completion)
1347 {
1348   GtkTreeViewColumn *column;
1349   GList *renderers;
1350
1351   if (GTK_WIDGET_MAPPED (completion->priv->popup_window))
1352     return;
1353
1354   if (!GTK_WIDGET_MAPPED (completion->priv->entry))
1355     return;
1356
1357   completion->priv->ignore_enter = TRUE;
1358     
1359   column = gtk_tree_view_get_column (GTK_TREE_VIEW (completion->priv->action_view), 0);
1360   renderers = gtk_tree_view_column_get_cell_renderers (column);
1361   gtk_widget_ensure_style (completion->priv->tree_view);
1362   g_object_set (GTK_CELL_RENDERER (renderers->data), "cell_background_gdk",
1363                 &completion->priv->tree_view->style->bg[GTK_STATE_NORMAL],
1364                 NULL);
1365   g_list_free (renderers);
1366
1367   gtk_widget_show_all (completion->priv->vbox);
1368
1369   _gtk_entry_completion_resize_popup (completion);
1370
1371   gtk_widget_show (completion->priv->popup_window);
1372     
1373   gtk_grab_add (completion->priv->popup_window);
1374   gdk_pointer_grab (completion->priv->popup_window->window, TRUE,
1375                     GDK_BUTTON_PRESS_MASK |
1376                     GDK_BUTTON_RELEASE_MASK |
1377                     GDK_POINTER_MOTION_MASK,
1378                     NULL, NULL, GDK_CURRENT_TIME);
1379 }
1380
1381 void
1382 _gtk_entry_completion_popdown (GtkEntryCompletion *completion)
1383 {
1384   if (!GTK_WIDGET_MAPPED (completion->priv->popup_window))
1385     return;
1386
1387   completion->priv->ignore_enter = FALSE;
1388   
1389   gdk_pointer_ungrab (GDK_CURRENT_TIME);
1390   gtk_grab_remove (completion->priv->popup_window);
1391
1392   gtk_widget_hide (completion->priv->popup_window);
1393 }
1394
1395 static gboolean 
1396 gtk_entry_completion_match_selected (GtkEntryCompletion *completion,
1397                                      GtkTreeModel       *model,
1398                                      GtkTreeIter        *iter)
1399 {
1400   gchar *str = NULL;
1401
1402   gtk_tree_model_get (model, iter, completion->priv->text_column, &str, -1);
1403   gtk_entry_set_text (GTK_ENTRY (completion->priv->entry), str);
1404   
1405   /* move cursor to the end */
1406   gtk_editable_set_position (GTK_EDITABLE (completion->priv->entry), -1);
1407   
1408   g_free (str);
1409
1410   return TRUE;
1411 }
1412
1413
1414 static gchar *
1415 gtk_entry_completion_compute_prefix (GtkEntryCompletion *completion)
1416 {
1417   GtkTreeIter iter;
1418   gchar *prefix = NULL;
1419   gboolean valid;
1420
1421   const gchar *key = gtk_entry_get_text (GTK_ENTRY (completion->priv->entry));
1422
1423   valid = gtk_tree_model_get_iter_first (GTK_TREE_MODEL (completion->priv->filter_model),
1424                                          &iter);
1425   
1426   while (valid)
1427     {
1428       gchar *text;
1429       
1430       gtk_tree_model_get (GTK_TREE_MODEL (completion->priv->filter_model),
1431                           &iter, completion->priv->text_column, &text,
1432                           -1);
1433
1434       if (g_str_has_prefix (text, key))
1435         {
1436           if (!prefix)
1437             prefix = g_strdup (text);
1438           else
1439             {
1440               gchar *p = prefix;
1441               const gchar *q = text;
1442               
1443               while (*p && *p == *q)
1444                 {
1445                   p++;
1446                   q++;
1447                 }
1448               
1449               *p = '\0';
1450             }
1451         }
1452       
1453       g_free (text);
1454       valid = gtk_tree_model_iter_next (GTK_TREE_MODEL (completion->priv->filter_model),
1455                                         &iter);
1456     }
1457
1458   return prefix;
1459 }
1460
1461
1462 static gboolean
1463 gtk_entry_completion_real_insert_prefix (GtkEntryCompletion *completion,
1464                                          gchar              *prefix)
1465 {
1466   if (prefix)
1467     {
1468       gint key_len;
1469       gint prefix_len;
1470       gint pos;
1471       const gchar *key;
1472
1473       prefix_len = g_utf8_strlen (prefix, -1);
1474
1475       key = gtk_entry_get_text (GTK_ENTRY (completion->priv->entry));
1476       key_len = g_utf8_strlen (key, -1);
1477
1478       if (prefix_len > key_len)
1479         {
1480           gtk_editable_insert_text (GTK_EDITABLE (completion->priv->entry),
1481                                     prefix + key_len, -1, &pos);
1482           gtk_editable_select_region (GTK_EDITABLE (completion->priv->entry),
1483                                       key_len, prefix_len);
1484
1485           completion->priv->has_completion = TRUE;
1486         }
1487     }
1488
1489   return TRUE;
1490 }
1491
1492 /**
1493  * gtk_entry_completion_insert_prefix:
1494  * @completion: a #GtkEntryCompletion
1495  * 
1496  * Requests a prefix insertion. 
1497  * 
1498  * Since: 2.6
1499  **/
1500 void
1501 gtk_entry_completion_insert_prefix (GtkEntryCompletion *completion)
1502 {
1503   gboolean done;
1504   gchar *prefix;
1505
1506   g_signal_handler_block (completion->priv->entry,
1507                           completion->priv->insert_text_id);
1508   prefix = gtk_entry_completion_compute_prefix (completion);
1509   if (prefix)
1510     {
1511       g_signal_emit (completion, entry_completion_signals[INSERT_PREFIX],
1512                      0, prefix, &done);
1513       g_free (prefix);
1514     }
1515   g_signal_handler_unblock (completion->priv->entry,
1516                             completion->priv->insert_text_id);
1517 }
1518
1519 /**
1520  * gtk_entry_completion_set_inline_completion:
1521  * @completion: a #GtkEntryCompletion
1522  * @inline_completion: %TRUE to do inline completion
1523  * 
1524  * Sets whether the common prefix of the possible completions should
1525  * be automatically inserted in the entry.
1526  * 
1527  * Since: 2.6
1528  **/
1529 void 
1530 gtk_entry_completion_set_inline_completion (GtkEntryCompletion *completion,
1531                                             gboolean            inline_completion)
1532 {
1533   g_return_if_fail (GTK_IS_ENTRY_COMPLETION (completion));
1534   
1535   inline_completion = inline_completion != FALSE;
1536
1537   if (completion->priv->inline_completion != inline_completion)
1538     {
1539       completion->priv->inline_completion = inline_completion;
1540
1541       g_object_notify (G_OBJECT (completion), "inline_completion");
1542     }
1543 }
1544
1545
1546 /**
1547  * gtk_entry_completion_get_inline_completion:
1548  * @completion: a #GtkEntryCompletion
1549  * 
1550  * Returns whether the common prefix of the possible completions should
1551  * be automatically inserted in the entry.
1552  * 
1553  * Return value: %TRUE if inline completion is turned on
1554  * 
1555  * Since: 2.6
1556  **/
1557 gboolean
1558 gtk_entry_completion_get_inline_completion (GtkEntryCompletion *completion)
1559 {
1560   g_return_val_if_fail (GTK_IS_ENTRY_COMPLETION (completion), FALSE);
1561   
1562   return completion->priv->inline_completion;
1563 }
1564
1565 /**
1566  * gtk_entry_completion_set_popup_completion:
1567  * @completion: a #GtkEntryCompletion
1568  * @popup_completion: %TRUE to do popup completion
1569  * 
1570  * Sets whether the completions should be presented in a popup window.
1571  * 
1572  * Since: 2.6
1573  **/
1574 void 
1575 gtk_entry_completion_set_popup_completion (GtkEntryCompletion *completion,
1576                                            gboolean            popup_completion)
1577 {
1578   g_return_if_fail (GTK_IS_ENTRY_COMPLETION (completion));
1579   
1580   popup_completion = popup_completion != FALSE;
1581
1582   if (completion->priv->popup_completion != popup_completion)
1583     {
1584       completion->priv->popup_completion = popup_completion;
1585
1586       g_object_notify (G_OBJECT (completion), "popup_completion");
1587     }
1588 }
1589
1590
1591 /**
1592  * gtk_entry_completion_get_popup_completion:
1593  * @completion: a #GtkEntryCompletion
1594  * 
1595  * Returns whether the completions should be presented in a popup window.
1596  * 
1597  * Return value: %TRUE if popup completion is turned on
1598  * 
1599  * Since: 2.6
1600  **/
1601 gboolean
1602 gtk_entry_completion_get_popup_completion (GtkEntryCompletion *completion)
1603 {
1604   g_return_val_if_fail (GTK_IS_ENTRY_COMPLETION (completion), TRUE);
1605   
1606   return completion->priv->popup_completion;
1607 }