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