/*
 *  Copyright (C) 2002  Ricardo Fernández Pascual
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2, or (at your option)
 *  any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include "location-entry.h"
#include "galeon-autocompletion-window.h"
#include "galeon-marshal.h"
#include "gul-gobject-misc.h"
#include "eel-gconf-extensions.h"
#include "prefs-strings.h"
#include "galeon-debug.h"

#include <gdk/gdkkeysyms.h>
#include <gtk/gtkclipboard.h>
#include <gtk/gtkentry.h>
#include <gtk/gtkimage.h>
#include <gtk/gtkimagemenuitem.h>
#include <gtk/gtkmain.h>
#include <gtk/gtkseparatormenuitem.h>
#include <gtk/gtkstock.h>
#include <gtk/gtkwindow.h>
#include <glib/gi18n.h>
#include <libgnomeui/gnome-entry.h>
#include <string.h>

/**
 * Private data
 */
struct _GaleonLocationEntryPrivate {
	GtkWidget *combo;
	GtkWidget *entry;
	gchar *before_completion;
	GaleonAutocompletion *autocompletion;
	GaleonAutocompletionWindow *autocompletion_window;
	gboolean autocompletion_window_visible;
	gint autocompletion_timeout;
	gint show_alternatives_timeout;
	gboolean block_set_autocompletion_key;
	gboolean hack_for_going_to_the_site_when_clicking_in_the_location_history;
	gboolean editing;

	gchar *autocompletion_key;
	gchar *last_completion;
};

#define AUTOCOMPLETION_DELAY 200
#define SHOW_ALTERNATIVES_DELAY 500

#define GALEON_LOCATION_ENTRY_HISTORY_ID	"galeon-url-history"

/**
 * Private functions, only availble from this file
 */
static void		galeon_location_entry_class_init	(GaleonLocationEntryClass *klass);
static void		galeon_location_entry_init		(GaleonLocationEntry *w);
static void		galeon_location_entry_finalize_impl	(GObject *o);
static void		galeon_location_entry_build		(GaleonLocationEntry *w);
static gboolean		galeon_location_entry_key_press_event_cb (GtkWidget *entry, GdkEventKey *event,
								  GaleonLocationEntry *w);
static void		galeon_location_entry_activate_cb	(GtkEntry *entry, GaleonLocationEntry *w);
static void		galeon_location_entry_autocompletion_sources_changed_cb (GaleonAutocompletion *aw,
										 GaleonLocationEntry *w);
static gint		galeon_location_entry_autocompletion_to (GaleonLocationEntry *w);
static gint		galeon_location_entry_autocompletion_show_alternatives_to (GaleonLocationEntry *w);
static void		galeon_location_entry_autocompletion_window_url_activated_cb
/***/								(GaleonAutocompletionWindow *aw, 
								 const gchar *url, 
								 gboolean new_tab_or_window,
								 GaleonLocationEntry *w);
static void		galeon_location_entry_list_event_after_cb (GtkWidget *list,
								   GdkEvent *event, 
								   GaleonLocationEntry *e);
static void		galeon_location_entry_editable_changed_cb (GtkEditable *editable, 
								   GaleonLocationEntry *e);
static void		galeon_location_entry_set_autocompletion_key (GaleonLocationEntry *e);
static void		galeon_location_entry_autocompletion_show_alternatives (GaleonLocationEntry *w);
static void		galeon_location_entry_autocompletion_hide_alternatives (GaleonLocationEntry *w);
static void		galeon_location_entry_autocompletion_window_hidden_cb (GaleonAutocompletionWindow *aw, 
									       GaleonLocationEntry *w);




static gpointer gtk_hbox_class;

/**
 * Signals enums and ids
 */
enum GaleonLocationEntrySignalsEnum {
	GALEON_LOCATION_ENTRY_URL_ACTIVATED,
	GALEON_LOCATION_ENTRY_LAST_SIGNAL
};
static gint GaleonLocationEntrySignals[GALEON_LOCATION_ENTRY_LAST_SIGNAL];

/**
 * GaleonLocationEntry object
 */

MAKE_GET_TYPE (galeon_location_entry, "GaleonLocationEntry", GaleonLocationEntry, 
	       galeon_location_entry_class_init, 
	       galeon_location_entry_init, GTK_TYPE_HBOX);

static void
galeon_location_entry_class_init (GaleonLocationEntryClass *klass)
{
	G_OBJECT_CLASS (klass)->finalize = galeon_location_entry_finalize_impl;
	gtk_hbox_class = g_type_class_peek_parent (klass);

	GaleonLocationEntrySignals[GALEON_LOCATION_ENTRY_URL_ACTIVATED] = g_signal_new (
		"url-activated", G_OBJECT_CLASS_TYPE (klass),  
		G_SIGNAL_RUN_FIRST | G_SIGNAL_RUN_LAST | G_SIGNAL_RUN_CLEANUP,
                G_STRUCT_OFFSET (GaleonLocationEntryClass, galeon_location_entry_url_activated), 
		NULL, NULL, 
		galeon_marshal_VOID__STRING_INT,
		G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_BOOLEAN);
}

static gboolean
focus_out_event_cb (GtkWidget *entry, GdkEventFocus *event, 
		    GaleonLocationEntry *w)
{
	w->priv->editing = FALSE;
	return FALSE;
}

static void
entry_clear_activate_cb (GtkMenuItem *item, GtkEntry *entry)
{
	gtk_entry_set_text (entry, "");
}

static void
entry_populate_popup_cb (GtkEntry *entry, GtkMenu *menu)
{
	GtkWidget *image;
	GtkWidget *menuitem;

	menuitem = gtk_separator_menu_item_new ();
	gtk_widget_show (menuitem);
	gtk_menu_shell_prepend (GTK_MENU_SHELL(menu), menuitem);

	/* Clear and Copy mnemonics conflict, make custom menuitem */
	image = gtk_image_new_from_stock (GTK_STOCK_CLEAR, GTK_ICON_SIZE_MENU);
	/* To translators: the mnemonic shouldn't conflict with any of the
	 * stock items in the GtkEntry context menu (Cut, Copy, Paste, Delete,
	 * and Insert Unicode control character.) */
	menuitem = gtk_image_menu_item_new_with_mnemonic (_("Cl_ear"));

	gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM(menuitem), image);

	g_signal_connect (G_OBJECT(menuitem), "activate",
			  G_CALLBACK(entry_clear_activate_cb), entry);

	gtk_widget_show (image);
	gtk_widget_show (menuitem);
	gtk_menu_shell_prepend (GTK_MENU_SHELL(menu), menuitem);
}

static void 
galeon_location_entry_init (GaleonLocationEntry *w)
{
	GaleonLocationEntryPrivate *p = g_new0 (GaleonLocationEntryPrivate, 1);
	w->priv = p;

	galeon_location_entry_build (w);

	g_signal_connect (w->priv->entry, "populate_popup",
			  G_CALLBACK (entry_populate_popup_cb), NULL);

	g_signal_connect (w->priv->entry, "focus_out_event",
			  G_CALLBACK (focus_out_event_cb), w);
}

static void
galeon_location_entry_finalize_impl (GObject *o)
{
	GaleonLocationEntry *w = GALEON_LOCATION_ENTRY (o);
	GaleonLocationEntryPrivate *p = w->priv;

	if (p->autocompletion)
	{
		g_signal_handlers_disconnect_matched (p->autocompletion, G_SIGNAL_MATCH_DATA, 0, 0, 
						      NULL, NULL, w);

		g_signal_handlers_disconnect_matched (p->autocompletion_window, G_SIGNAL_MATCH_DATA, 0, 0, 
						      NULL, NULL, w);

		g_object_unref (G_OBJECT (p->autocompletion));
		g_object_unref (G_OBJECT (p->autocompletion_window)); 
	}

	g_free (p->last_completion);
	g_free (p->before_completion);
	g_free (p->autocompletion_key);
	LOG ("GaleonLocationEntry finalized");

	g_free (p);	
	G_OBJECT_CLASS (gtk_hbox_class)->finalize (o);
}

GaleonLocationEntry *
galeon_location_entry_new (void)
{
	return GALEON_LOCATION_ENTRY (g_object_new (GALEON_TYPE_LOCATION_ENTRY, NULL));
}

void
galeon_location_entry_clear_history (void)
{
	GtkWidget *w;

	w = gnome_entry_new (GALEON_LOCATION_ENTRY_HISTORY_ID);
	gnome_entry_clear_history (GNOME_ENTRY (w));
	gtk_widget_destroy (w);
}

static void
galeon_location_entry_build (GaleonLocationEntry *w)
{
	GaleonLocationEntryPrivate *p = w->priv;
	GtkWidget *list;

	p->combo = gnome_entry_new (GALEON_LOCATION_ENTRY_HISTORY_ID);
	p->entry = GTK_COMBO (p->combo)->entry;
	gtk_widget_show (p->combo);
	gtk_box_pack_start (GTK_BOX (w), p->combo, TRUE, TRUE, 0);

	g_signal_connect (p->entry, "key-press-event", 
			  G_CALLBACK (galeon_location_entry_key_press_event_cb), w);

	g_signal_connect (p->entry, "activate", 
			  G_CALLBACK (galeon_location_entry_activate_cb), w);

	g_signal_connect (p->entry, "changed", 
			  G_CALLBACK (galeon_location_entry_editable_changed_cb), w);

	list = GTK_COMBO (p->combo)->list;
	
	g_signal_connect_after (list, "event-after", 
				G_CALLBACK (galeon_location_entry_list_event_after_cb), w);

}

static gint
galeon_location_entry_autocompletion_show_alternatives_to (GaleonLocationEntry *w)
{
	GaleonLocationEntryPrivate *p = w->priv;
	if (p->autocompletion)
	{
		LOG ("+galeon_location_entry_autocompletion_show_alternatives_to");
		galeon_location_entry_set_autocompletion_key (w);
		galeon_location_entry_autocompletion_show_alternatives (w);
	}
	p->show_alternatives_timeout = 0;
	return FALSE;
}

static void
galeon_location_entry_autocompletion_hide_alternatives (GaleonLocationEntry *w)
{
	GaleonLocationEntryPrivate *p = w->priv;
	if (p->autocompletion_window)
	{
		galeon_autocompletion_window_hide (p->autocompletion_window);
		p->autocompletion_window_visible = FALSE;
	}
}

static void
galeon_location_entry_autocompletion_show_alternatives (GaleonLocationEntry *w)
{
	GaleonLocationEntryPrivate *p = w->priv;
	if (p->autocompletion_window)
	{
		galeon_autocompletion_window_show (p->autocompletion_window);
		p->autocompletion_window_visible = TRUE;
	}
}

static void
galeon_location_entry_autocompletion_unselect_alternatives (GaleonLocationEntry *w)
{
	GaleonLocationEntryPrivate *p = w->priv;
	if (p->autocompletion_window)
	{
		galeon_autocompletion_window_unselect (p->autocompletion_window);
	}
}

static gint
galeon_location_entry_autocompletion_to (GaleonLocationEntry *w)
{
	GaleonLocationEntryPrivate *p = w->priv;
	gchar *text;
	gchar *common_prefix;
	
	LOG ("in galeon_location_entry_autocompletion_to");

	galeon_location_entry_set_autocompletion_key (w);

	{
		GtkEditable *editable = GTK_EDITABLE (p->entry);
		gint sstart, send;
		gint pos = gtk_editable_get_position (editable);
		const gchar *text = gtk_entry_get_text (GTK_ENTRY (p->entry));
		gint text_len = strlen (text);
		gtk_editable_get_selection_bounds (editable, &sstart, &send);
		
		if (pos != text_len
		    || send != text_len)
		{
			/* the user is editing the entry, don't mess it */
			LOG ("The user seems editing the text: pos = %d, "
			     "strlen (text) = %d, sstart = %d, send = %d", 
			     pos, strlen (text), sstart, send);
			p->autocompletion_timeout = 0;
			return FALSE;
		}		
	}

	common_prefix = galeon_autocompletion_get_common_prefix (p->autocompletion);

	LOG ("common_prefix: %s", common_prefix);

	if (common_prefix && (!p->before_completion || p->before_completion[0] == '\0'))
	{
		text = galeon_location_entry_get_location (w);
		g_free (p->before_completion);
		p->before_completion = text;
	}

	if (common_prefix)
	{
		/* check original length */
		guint text_len = strlen (p->autocompletion_key);
		
		p->block_set_autocompletion_key = TRUE;

		/* set entry to completed text */
		gtk_entry_set_text (GTK_ENTRY (p->entry), common_prefix);
		
		/* move selection appropriately */
		gtk_editable_select_region (GTK_EDITABLE (p->entry), text_len, -1);
		
		p->block_set_autocompletion_key = FALSE;

		g_free (p->last_completion);
		p->last_completion = common_prefix;
	}

	p->autocompletion_timeout = 0;
	return FALSE;
}

static void
real_set_location (GaleonLocationEntry *w,
		   const gchar *new_location)
{
	GaleonLocationEntryPrivate *p = w->priv;
	int pos = 0;
	int start, end;
	gchar* selection = NULL;

	/* Get the current selection, it is removed when we do the delete_text 
	 * below */
	if (gtk_editable_get_selection_bounds (GTK_EDITABLE (p->entry), &start, &end))
	{
		selection = gtk_editable_get_chars (GTK_EDITABLE (p->entry), start, end);
	}

	gtk_editable_delete_text (GTK_EDITABLE (p->entry), 0, -1);
	gtk_editable_insert_text (GTK_EDITABLE (p->entry), new_location, 
			          strlen (new_location), &pos);

	/* Restore the selection into the PRIMARY clipboard as it will have just
	 * been wiped */
	if (selection)
	{
		gtk_clipboard_set_text (gtk_clipboard_get (GDK_SELECTION_PRIMARY),
					selection, strlen (selection));
		g_free (selection);
	}
}

static void
emit_activated_signal (GaleonLocationEntry *w, const char *url, gboolean new_tab_or_window)
{
	w->priv->editing = FALSE;

	g_signal_emit (w, GaleonLocationEntrySignals[GALEON_LOCATION_ENTRY_URL_ACTIVATED], 
                       0, url, new_tab_or_window);
}


/* this is from the old location entry, need to do the autocompletion before implementing this */
static gboolean
galeon_location_entry_key_press_event_cb (GtkWidget *entry, GdkEventKey *event, GaleonLocationEntry *w)
{
	GaleonLocationEntryPrivate *p = w->priv;
        static gboolean suggest = FALSE;

        if (p->autocompletion_timeout != 0)
	{
                gtk_timeout_remove (p->autocompletion_timeout);
		p->autocompletion_timeout = 0;
	}

        if (p->show_alternatives_timeout != 0)
	{
                gtk_timeout_remove (p->show_alternatives_timeout);
		p->show_alternatives_timeout = 0;
	}
	
        /* only suggest heuristic completions if TAB is hit twice */
        if (event->keyval != GDK_Tab)
	{
                suggest = FALSE;
	}
	

	/* Handle any CTRL+Enter events */
	if ( event->state & GDK_CONTROL_MASK && 
	     ( event->keyval == GDK_KP_Enter || event->keyval == GDK_Return ) )
	{
		char *url = gtk_editable_get_chars (GTK_EDITABLE(entry), 0, -1);

		LOG ("In galeon_location_key_press_cb, going to %s", url);
		   
		galeon_location_entry_autocompletion_hide_alternatives (w);

		emit_activated_signal (w, url, TRUE);

		g_free (url);

		return TRUE;
	}

	/* Ingore any CTRL+<key> commands (or backspace commands) */
        if ((event->state & GDK_CONTROL_MASK) ||
            (event->state == 0 && event->keyval == GDK_BackSpace))
        {
		galeon_location_entry_autocompletion_hide_alternatives (w);
                return FALSE;
        }

        /* don't grab alt combos, thus you can still access the menus. */
        if (event->state & GDK_MOD1_MASK)
        {
		galeon_location_entry_autocompletion_hide_alternatives (w);
                return FALSE;
        }

        /* make sure the end key works at all times */ 
        if ((!((event->state & GDK_SHIFT_MASK) ||
	       (event->state & GDK_CONTROL_MASK) ||
	       (event->state & GDK_MOD1_MASK)) 
	     && (event->keyval == GDK_End)))
        {
		galeon_location_entry_autocompletion_hide_alternatives (w);
                gtk_editable_select_region (GTK_EDITABLE (p->entry), 0, 0); 
                gtk_editable_set_position (GTK_EDITABLE (p->entry), -1);
		galeon_location_entry_autocompletion_unselect_alternatives (w);
                return TRUE;
        }

	switch (event->keyval)
        {
        case GDK_Left:
        case GDK_Right:
		galeon_location_entry_autocompletion_hide_alternatives (w);
                return FALSE;
        case GDK_Up:
        case GDK_Down:
        case GDK_Page_Up:
        case GDK_Page_Down:
		galeon_location_entry_autocompletion_hide_alternatives (w);
                /* galeon_embed_grab_focus (window->active_embed); */
                return FALSE;
        case GDK_Tab:
        {
                gchar *common_prefix = NULL;
                gchar *text;

		galeon_location_entry_set_autocompletion_key (w);

                gtk_editable_delete_selection (GTK_EDITABLE (p->entry));
                text = galeon_location_entry_get_location (w);
		galeon_location_entry_autocompletion_unselect_alternatives (w);

		/*
		 * TODO: heuristic completions like in galeon1 are missing
		 * common_prefix = 
		 *     auto_completion_complete_url_extended (text, suggest);
		 */

		if (p->autocompletion)
		{
			common_prefix = galeon_autocompletion_get_common_prefix (p->autocompletion);
		}
                suggest = FALSE;
                if (common_prefix)
                {
                        if (!p->before_completion) 
			{
                                p->before_completion = g_strdup (text);
			}

                        p->block_set_autocompletion_key = TRUE;

			gtk_entry_set_text (GTK_ENTRY (p->entry), common_prefix);
			gtk_editable_set_position (GTK_EDITABLE (p->entry), -1);

                        p->block_set_autocompletion_key = FALSE;

			/* show alternatives list only if there is no
			 * non-ambiguous prefix we can complete
			 */
                        if (!strcmp (common_prefix, text))
                        {
				galeon_location_entry_autocompletion_show_alternatives (w);
                                /* really suggest something the next time */
                                suggest = TRUE; 
                        }
			else if (p->autocompletion_window_visible)
			{
				/* if the alternatives list is already visible,
				 * update its contents to match the new prefix
				 */
				galeon_location_entry_autocompletion_show_alternatives (w);
			}
                        g_free (common_prefix);
                }
                else
                {
			galeon_location_entry_autocompletion_hide_alternatives (w);
                }
		g_free (text);
                return TRUE;
        }
        case GDK_Escape:
		galeon_location_entry_autocompletion_hide_alternatives (w);
                if (p->before_completion)
                {
                        real_set_location (w, p->before_completion);
                        g_free (p->before_completion);
                        p->before_completion = NULL;
			gtk_editable_set_position (GTK_EDITABLE (p->entry), -1);
                        return TRUE;
                }
                else
                {
                        /* real_set_location (w, embed->location); */
                }
                break;
        default:
		/* ignore keys that don't generate content (Shift, Ctrl, ...) */
		if (event->length <= 0) break;

		w->priv->editing = TRUE;
		galeon_location_entry_autocompletion_unselect_alternatives (w);
		if ((eel_gconf_get_boolean (CONF_COMPLETION_SHOW_LIST_AUTO))
		    && (event->string[0] > 32) && (event->string[0] < 126))
                {
                        p->show_alternatives_timeout = g_timeout_add 
                                (SHOW_ALTERNATIVES_DELAY, 
				 (GSourceFunc) galeon_location_entry_autocompletion_show_alternatives_to, w);
                }
		if ((event->string[0] > 32) && (event->string[0] < 126)
		    && eel_gconf_get_boolean (CONF_HISTORY_AUTOCOMP_ENABLE)
		    && p->autocompletion)
		{
			p->autocompletion_timeout = gtk_timeout_add 
				(AUTOCOMPLETION_DELAY, 
				 (GSourceFunc) galeon_location_entry_autocompletion_to, w);
		}
                break;
        }

        return FALSE;
}

static void
galeon_location_entry_activate_cb (GtkEntry *entry, GaleonLocationEntry *w)
{
	char *url;

	url = gtk_editable_get_chars (GTK_EDITABLE(entry), 0, -1);

	galeon_location_entry_autocompletion_hide_alternatives (w);

	LOG ("In galeon_location_entry_activate_cb, going to %s", url);

	emit_activated_signal (w, url, FALSE);

	g_free (url);
}

static void
galeon_location_entry_autocompletion_sources_changed_cb (GaleonAutocompletion *aw,
							 GaleonLocationEntry *w)
{
	GaleonLocationEntryPrivate *p = w->priv;

	LOG ("in galeon_location_entry_autocompletion_sources_changed_cb");

        if (p->autocompletion_timeout == 0
	    && p->last_completion
	    && !strcmp (p->last_completion, gtk_entry_get_text (GTK_ENTRY (p->entry))))
	{
		p->autocompletion_timeout = gtk_timeout_add 
			(AUTOCOMPLETION_DELAY, 
			 (GSourceFunc) galeon_location_entry_autocompletion_to, w);
	}

        if (p->show_alternatives_timeout == 0 
	    && p->autocompletion_window_visible)
	{
 		p->show_alternatives_timeout = gtk_timeout_add 
			(SHOW_ALTERNATIVES_DELAY, 
			 (GSourceFunc) galeon_location_entry_autocompletion_show_alternatives_to, w);
	}
}

void
galeon_location_entry_set_location (GaleonLocationEntry *w, 
				    const gchar *new_location)
{
	if (!w->priv->editing)
	{
		real_set_location (w, new_location);
	}
}

gchar *
galeon_location_entry_get_location (GaleonLocationEntry *w)
{
	char *location = gtk_editable_get_chars (GTK_EDITABLE (w->priv->entry), 0, -1);
	return location;
}

void
galeon_location_entry_set_autocompletion (GaleonLocationEntry *w, 
					  GaleonAutocompletion *ac)
{
	GaleonLocationEntryPrivate *p = w->priv;
	if (p->autocompletion)
	{
		g_signal_handlers_disconnect_matched (p->autocompletion, G_SIGNAL_MATCH_DATA, 0, 0, 
						      NULL, NULL, w);

		g_signal_handlers_disconnect_matched (p->autocompletion_window, G_SIGNAL_MATCH_DATA, 0, 0, 
						      NULL, NULL, w);

		g_object_unref (G_OBJECT (p->autocompletion));
		g_object_unref (p->autocompletion_window);
	}
	p->autocompletion = ac;
	if (p->autocompletion)
	{
		g_object_ref (G_OBJECT (p->autocompletion));
		p->autocompletion_window = galeon_autocompletion_window_new (p->autocompletion, 
									     p->entry);
		g_signal_connect (p->autocompletion_window, "url-activated",
				  G_CALLBACK (galeon_location_entry_autocompletion_window_url_activated_cb),
				  w);

		g_signal_connect (p->autocompletion_window, "hidden",
				  G_CALLBACK (galeon_location_entry_autocompletion_window_hidden_cb),
				  w);

		g_signal_connect (p->autocompletion, "sources-changed",
				  G_CALLBACK (galeon_location_entry_autocompletion_sources_changed_cb),
				  w);

		galeon_location_entry_set_autocompletion_key (w);
	}

}

static void
galeon_location_entry_autocompletion_window_url_activated_cb (GaleonAutocompletionWindow *aw, 
							      const gchar *url, 
							      gboolean new_tab_or_window,
							      GaleonLocationEntry *w)
{
	real_set_location (w, url);

	LOG ("In location_entry_autocompletion_window_url_activated_cb, going to %s", url);

	galeon_location_entry_autocompletion_hide_alternatives (w);

	emit_activated_signal (w, url, new_tab_or_window);
}

static void
galeon_location_entry_autocompletion_window_hidden_cb (GaleonAutocompletionWindow *aw, 
						       GaleonLocationEntry *w)
{
	GaleonLocationEntryPrivate *p = w->priv;

	LOG ("In location_entry_autocompletion_window_hidden_cb");

	p->autocompletion_window_visible = FALSE;

	if (p->show_alternatives_timeout)
	{
		g_source_remove (p->show_alternatives_timeout);
		p->show_alternatives_timeout = 0;
	}

	if (p->autocompletion_timeout)
	{
		g_source_remove (p->autocompletion_timeout);
		p->autocompletion_timeout = 0;
	}
}

void
galeon_location_entry_edit (GaleonLocationEntry *w)
{
	w->priv->editing = TRUE;
	/* gtk_editable_select_region (GTK_EDITABLE(w->priv->entry), 0, -1); */
	gtk_widget_grab_focus (w->priv->entry);
}

static void
galeon_location_entry_list_event_after_cb (GtkWidget *list,
					   GdkEvent *event, 
					   GaleonLocationEntry *e)
{
	if (event->type == GDK_BUTTON_PRESS
	    && ((GdkEventButton *) event)->button == 1)
	{
		GaleonLocationEntryPrivate *p = e->priv;
		p->hack_for_going_to_the_site_when_clicking_in_the_location_history = TRUE;
	}
}

static void
galeon_location_entry_editable_changed_cb (GtkEditable *editable, GaleonLocationEntry *e)
{
	GaleonLocationEntryPrivate *p = e->priv;
	galeon_location_entry_set_autocompletion_key (e);

	if (p->hack_for_going_to_the_site_when_clicking_in_the_location_history)
	{
		gchar *url = galeon_location_entry_get_location (e);
		if (url && url[0] != '\0')
		{
			p->hack_for_going_to_the_site_when_clicking_in_the_location_history = FALSE;
			emit_activated_signal (e, url, FALSE);
			g_free (url);
		}
	}

}

static void
galeon_location_entry_set_autocompletion_key (GaleonLocationEntry *e)
{
	GaleonLocationEntryPrivate *p = e->priv;
	if (p->autocompletion && !p->block_set_autocompletion_key)
	{
		GtkEditable *editable = GTK_EDITABLE (p->entry);
		gint sstart, send;
		gchar *text;
		gtk_editable_get_selection_bounds (editable, &sstart, &send);
		text = gtk_editable_get_chars (editable, 0, sstart);
		galeon_autocompletion_set_key (p->autocompletion, text);
		g_free (p->autocompletion_key);
		p->autocompletion_key = text;
	}
}

