/*
 *  Copyright (C) 2000 Marco Pesenti Gritti
 *
 *  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.
 */

/* Galeon includes */
#include "galeon.h"
#include "window.h"
#include "session.h"
#include "embed.h"
#include "dialog.h"
#include "misc.h"
#include "menubar.h"
#include "toolbar.h"
#include "history.h"
#include "bookmarks.h"
#include "prefs.h"
#include "find.h"
#include "glade.h"
#include "filepicker.h"
#include "mozilla_i18n.h"
#include "spinner.h"
#include "window_notifiers.h"
#include "themes.h"

#include <string.h>
#include <time.h>

#include <gtk/gtkdnd.h>
#include <gtk/gtkpaned.h>
#include <gtkmozembed.h>

/* GNOME includes */
#include <libgnomeui/gnome-animator.h>
#include <libgnomeui/gnome-preferences.h>
#include <libgnome/gnome-util.h>
#include <libgnomeui/gnome-winhints.h>
#include <libgnomeui/gnome-dialog-util.h>
#include <libgnomeui/gnome-window-icon.h>
#include <libgnome/gnome-config.h>
#include <libgnome/gnome-i18n.h>
#include <libgnomevfs/gnome-vfs.h>
#include <libgnomevfs/gnome-vfs-uri.h>

#ifdef HAVE_XINERAMA
#include <X11/X.h>
#include <X11/Xlib.h>
#include <gdk/gdkx.h>
#include <X11/extensions/Xinerama.h>
#endif

/* indicates a window is in fullscreen mode */
gboolean fullscreen_active = FALSE;


/* local function prototypes */
static void window_init_data (GaleonWindow *window);
static void window_set_menu_data (GaleonWindow *window);
static void window_menubar_create (GaleonWindow *window);
static void window_toolbars_create (GaleonWindow *window);
static void window_set_selection_signals (GaleonWindow *window);
static void window_create_embed_container (GaleonWindow *window);
static void window_set_chrome (GaleonWindow *window, guint32 chrome_mask);
static void window_init_menu_data (GaleonWindow *window);
static void window_statusbar_create (GaleonWindow *window);
static gint strcasestr_cb (gconstpointer a, gconstpointer b);
static GtkWidget *window_notebook_tab_new (GaleonEmbed *embed,
					   const gchar *title);
static GtkWidget *window_session_history_menuitem (gchar *file, gint index);
static void window_session_history_menu_remove (GaleonWindow *window);

/* callbacks used here */
void file_open_ok_button_clicked_cb (const gchar *file, gpointer data);

/* the types which can be dropped either into the GtkMozEmbed or onto
 * the location entry field */
const GtkTargetEntry drop_types[] =
{
	{ "GALEON_URL",    0, DND_TARGET_GALEON_URL    },
	{ "text/uri-list", 0, DND_TARGET_TEXT_URI_LIST },
	{ "_NETSCAPE_URL", 0, DND_TARGET_NETSCAPE_URL  },
	{ "STRING",        0, DND_TARGET_STRING        }
};
const gint drop_types_num_items = (sizeof (drop_types) / 
				   sizeof (GtkTargetEntry));

/* the types which can be dragged from various places in Galeon, such as
 * the bookmarks editor, the toolbar bookmark icon, and the history */
const GtkTargetEntry url_drag_types[] = 
{
	{ "GALEON_BOOKMARK", 0, DND_TARGET_GALEON_BOOKMARK },
	{ "GALEON_URL",      0, DND_TARGET_GALEON_URL      },
	{ "_NETSCAPE_URL",   0, DND_TARGET_NETSCAPE_URL    },
	{ "STRING",          0, DND_TARGET_STRING          }
};
const gint url_drag_types_num_items = (sizeof (url_drag_types) /
				       sizeof (GtkTargetEntry));

typedef enum
{
	STRING,
	COMPOUND_TEXT
} SelType;

/* selection types */
const GtkTargetEntry selection_types[] =
{
	{ "STRING",        0, STRING        },
	{ "COMPOUND_TEXT", 0, COMPOUND_TEXT }
};
const gint selection_types_num_targets = (sizeof (selection_types) /
					  sizeof (GtkTargetEntry));


/**
 * window_load_url: load a URL into the active embed of a window
 */
void
window_load_url (GaleonWindow *window, const gchar *url)
{
	/* check arguments */
	return_if_not_window (window);

	/* load into the active GaleonEmbed */
	embed_load_url (window->active_embed, url);
}

/**
 * window_clear_url_entry: clear the window URL entry field
 */
void window_clear_url_entry (GaleonWindow *window)
{
	if (window->location_entry != NULL)
	{	
		gtk_editable_delete_text 
			(GTK_EDITABLE (window->location_entry), 0, -1);
	}
}

/**
 * window_set_url_entry: fill the window URL entry field
 */
void window_set_url_entry (GaleonWindow *window, const gchar *location)
{
	if (window->location_entry != NULL)
	{
		gtk_entry_set_text 
			(GTK_ENTRY (window->location_entry), location);
	}
}

/**
 * window_create: create a browser structure and main window, 
 * but without an embedding widget. Should only be called from
 * embed_create
 */
GaleonWindow *
window_create (guint32 chrome_mask)
{
        GaleonWindow *window;
	gchar *file;
	
	/* allocate and initialise the GaleonWindow structure */
	window = g_new0 (GaleonWindow, 1);

	/* set magic */
	window->magic = GALEON_WINDOW_MAGIC;

	window_set_chrome (window, chrome_mask);

	/* create the browser window */
	window->WMain = gnome_app_new ("galeon", _("Galeon"));
	gtk_window_set_wmclass (GTK_WINDOW (window->WMain), "Galeon",
				"galeon_browser");

	/* init dialogs data */
	window->print_dialog = NULL;

	window->layered = FALSE;

	/* initialize GaleonWindow data */
	window_init_data (window);

	/* create the statusbar */
	window_statusbar_create (window);

	/* get the dock */
	window->dock = GNOME_APP (window->WMain)->dock;
	window->dock_type = DOCK_NONE;

	/* clear drag signals */
	window->drag_motion_signal = 0;
	window->drag_leave_signal = 0;
	window->in_predrag = FALSE;
	window->in_drag = FALSE;

	/* the spinner isn't running yet */
	window->spinner_running = 0;

	/* save the toolbar and menubar layout */
	window_save_layout (window);

	/* create the toolbar */
	window_toolbars_create (window);

	/* create the menubar */
	window_menubar_create (window);

	/* add notifiers for the window */
	window_init_notifiers(window);

	/* restore the toolbar and menubar layout */
	window_restore_layout (window);

	/* set mini icon */
	file = gnome_pixmap_file ("galeon.png");
	gnome_window_icon_set_from_file (GTK_WINDOW (window->WMain), file);
	g_free (file);

	/* set window policies regarding resizing */
	gtk_window_set_policy (GTK_WINDOW (window->WMain), TRUE, TRUE, TRUE);

	/* so widgets can look the data up */
	gtk_object_set_data (GTK_OBJECT (window->WMain), "GaleonWindow",
			     window);

	/* connect the delete signal handler*/
	gtk_signal_connect(GTK_OBJECT(window->WMain), "delete-event",
			   GTK_SIGNAL_FUNC(window_delete_cb),
			   window);

	gtk_signal_connect(GTK_OBJECT(window->WMain), "key-press-event",
			   GTK_SIGNAL_FUNC(window_key_press_event),
			   window);

	/* NB: window isn't shown until we add an embed */
	/* don't know the size at which to show it yet -- if we discover
	 * a size (e.g. for a popup) then we'll use that, otherwise we'll
	 * find a default, but not until the window is made visible */
	window->set_size = FALSE;

	/* add to session */
	session_add_window (window);

	/* setup selection signals */
	window_set_selection_signals (window);

	/* create widgets used to pack embeds in */
	window_create_embed_container (window);

	/* setup visibility according to config */
	if (!eel_gconf_get_boolean (CONF_WINDOWS_SHOW_TOOLBARS) ||
	    !window->toolBarOn)
	{
		window_toolbar_hide (window);
	}
	if (!eel_gconf_get_boolean (CONF_WINDOWS_SHOW_MENUBAR) ||
	    !window->menuBarOn)
	{
		window_menubar_hide (window);
	}
	if (!eel_gconf_get_boolean (CONF_WINDOWS_SHOW_STATUSBAR) ||
	    !window->statusBarOn)
	{
		window_statusbar_hide (window);
	}
	if (!eel_gconf_get_boolean (CONF_WINDOWS_SHOW_BOOKMARKS) ||
	    !window->toolBarOn)
	{
		bookmarks_toolbars_set_visibility (window, FALSE);
		if (window->hbox)
		{
			gtk_widget_queue_resize (GTK_WIDGET (window->hbox));
		}
	}
	if (eel_gconf_get_boolean (CONF_WINDOWS_SHOW_HISTORY_DOCK))
	{
		history_show_dock (window);
	}
	if (eel_gconf_get_boolean (CONF_WINDOWS_SHOW_BOOKMARKS_DOCK))
	{
		bookmarks_editor_show_dock (window);
	}
	
	/* return the completed GaleonWindow */
	return window;
}

/**
 * window_init_data: init GaleonWindow data structure
 */
static void
window_init_data (GaleonWindow *window)
{
	/* these are all nullified */
	window->spinner = NULL;
	window->tempMessage = NULL;
	window->bookmarks_toolbars = NULL;
	window->bookmarks_tooltips = NULL;
}

static void
window_init_menu_data (GaleonWindow *window)
{
	/* menus */
	window->file_menu =
		GTK_MENU_ITEM (menubar_uiinfo[0].widget)->submenu;
	window->bookmarks_menu = 
		GTK_MENU_ITEM (menubar_uiinfo[5].widget)->submenu;
	window->go_menu = 
		GTK_MENU_ITEM (menubar_uiinfo[6].widget)->submenu;
		
	/* file menu */
	window->file_session_history_separator_sup = NULL; // not yet created
	window->file_session_history_separator_inf =
		file_menu_uiinfo[12].widget;
		
	/* edit menu */
	window->edit_cut = edit_menu_uiinfo[0].widget;
	window->edit_copy = edit_menu_uiinfo[1].widget;
	window->edit_paste = edit_menu_uiinfo[2].widget;

	/* view menu */
	window->view_menubar = view_menu_uiinfo[0].widget;
	window->view_toolbar = view_menu_uiinfo[1].widget;
	window->view_bookmarks = view_menu_uiinfo[2].widget;
	window->view_statusbar = view_menu_uiinfo[3].widget;
	window->view_fullscreen = view_menu_uiinfo[4].widget;
	window->encoding = view_menu_uiinfo[7].widget;
	window->csslist = view_menu_uiinfo[8].widget;

	/* tab menu */
	window->detach_tab = tab_menu_uiinfo[0].widget;
	window->move_tab_to_window_menu = tab_menu_uiinfo[1].widget;
	window->prev_tab = tab_menu_uiinfo[3].widget;
	window->next_tab = tab_menu_uiinfo[4].widget;
	window->move_tab_left = tab_menu_uiinfo[6].widget;
	window->move_tab_right = tab_menu_uiinfo[7].widget;

	/* settings menu */
	window->load_images_always = load_images_always_uiinfo[0].widget;
	window->load_images_from_current_server_only = 
					load_images_always_uiinfo[1].widget;
	window->load_images_never = load_images_always_uiinfo[2].widget;

	window->animate_always = animate_always_uiinfo[0].widget;
	window->animate_once_through = animate_always_uiinfo[1].widget;
	window->animate_never = animate_always_uiinfo[2].widget;

	window->no_proxy = proxies_always_uiinfo[0].widget;
	window->manual_proxy = proxies_always_uiinfo[1].widget;
	window->autoproxy = proxies_always_uiinfo[2].widget;
	  
	window->use_own_fonts =  settings_menu_uiinfo[4].widget;
	window->use_own_colors = settings_menu_uiinfo[5].widget;
	window->enable_java = settings_menu_uiinfo[6].widget;
	window->enable_javascript = settings_menu_uiinfo[7].widget;
	window->allow_popups = settings_menu_uiinfo[8].widget;

	/* bookmarks menu */
	window->add_bookmark = bookmarks_menu_uiinfo[1].widget;
	window->bookmarks_separator = bookmarks_menu_uiinfo[3].widget;

	/* go menu */
	window->back_menuitem = go_menu_uiinfo[0].widget;
	window->forward_menuitem = go_menu_uiinfo[1].widget;
	window->up_menuitem = go_menu_uiinfo[2].widget;
	window->refresh_menuitem = go_menu_uiinfo[3].widget;
	window->homepage_menuitem = go_menu_uiinfo[4].widget;

	/* tools menu */
#ifdef ENABLE_EXPERIMENTAL_FILTERS
	window->java_console = tools_menu_uiinfo[7].widget;
#else
	window->java_console = tools_menu_uiinfo[6].widget;
#endif

	window->open_url_entry = NULL;

	/* connect signal for the move_tab_to_window_menu */
	gtk_signal_connect (GTK_OBJECT (window->move_tab_to_window_menu),
			    "activate", window_move_tab_to_window_menu_cb,
			    window);
	gtk_menu_item_set_submenu
		(GTK_MENU_ITEM (window->move_tab_to_window_menu),
		 gtk_menu_new ());

	/* connect signals for go menu */
	gtk_signal_connect (GTK_OBJECT (go_menu_uiinfo[0].widget),
			    "button-press-event",
			    GTK_SIGNAL_FUNC
			   	(window_back_forward_button_press_cb),
			    window);
	gtk_signal_connect (GTK_OBJECT (go_menu_uiinfo[1].widget),
			    "button-press-event",
			    GTK_SIGNAL_FUNC
			   	(window_back_forward_button_press_cb),
			    window);
	gtk_signal_connect (GTK_OBJECT (go_menu_uiinfo[2].widget),
			    "button-press-event",
			    GTK_SIGNAL_FUNC
			   	(window_up_button_press_event_cb),
			    window);
	gtk_signal_connect (GTK_OBJECT (go_menu_uiinfo[3].widget),
			    "button-press-event",
			    GTK_SIGNAL_FUNC
			   	(window_refresh_button_press_event_cb),
			    window);
	gtk_signal_connect (GTK_OBJECT (go_menu_uiinfo[4].widget),
			    "button-press-event",
			    GTK_SIGNAL_FUNC
			   	(window_home_button_press_event_cb),
			    window);
	gtk_signal_connect (GTK_OBJECT (go_menu_uiinfo[0].widget),
			    "button-release-event",
			    GTK_SIGNAL_FUNC
			   	(window_back_forward_button_release_cb),
			    window);
	gtk_signal_connect (GTK_OBJECT (go_menu_uiinfo[1].widget),
			    "button-release-event",
			    GTK_SIGNAL_FUNC
			    	(window_back_forward_button_release_cb),
			    window);
	gtk_signal_connect (GTK_OBJECT (go_menu_uiinfo[2].widget),
			    "button-release-event",
			    GTK_SIGNAL_FUNC
			    	(window_up_button_release_event_cb),
			    window);
	gtk_signal_connect (GTK_OBJECT (go_menu_uiinfo[3].widget),
			    "button-release-event",
			    GTK_SIGNAL_FUNC
			    	(window_refresh_button_release_event_cb),
			    window);
	gtk_signal_connect (GTK_OBJECT (go_menu_uiinfo[4].widget),
			    "button-release-event",
			    GTK_SIGNAL_FUNC
			    	(window_home_button_release_event_cb),
			    window);

	/* connect signals for help menu */
	gtk_signal_connect (GTK_OBJECT (help_menu_uiinfo[1].widget),
			    "button-release-event",
			    window_menu_help_homepage_release_cb,
			    window);
	gtk_signal_connect (GTK_OBJECT (help_menu_uiinfo[2].widget),
			    "button-release-event",
			    window_menu_help_bugreport_release_cb,
			    window);
	gtk_signal_connect (GTK_OBJECT (help_menu_uiinfo[3].widget),
			    "button-release-event",
			    window_menu_help_about_plugins_release_cb,
			    window);
}

static void
window_menubar_create (GaleonWindow *window)
{
        g_assert (window->WMain);

	/* need to set the user_data field in all the GnomeUIInfo structs */
	window_set_menu_data (window);

	gnome_app_create_menus (GNOME_APP(window->WMain), 
				menubar_uiinfo);

	window->menubar = GNOME_APP(window->WMain)->menubar;

	window_init_menu_data (window);

	gnome_app_install_menu_hints (GNOME_APP(window->WMain), 
				      menubar_uiinfo);

	bookmarks_menu_create (window);
	window_session_history_menu_create (window);

	gtk_check_menu_item_set_active 
		(GTK_CHECK_MENU_ITEM (window->view_menubar),
		 window->menuBarOn ?
		 eel_gconf_get_boolean (CONF_WINDOWS_SHOW_MENUBAR) :
		 FALSE);
	gtk_check_menu_item_set_active 
		(GTK_CHECK_MENU_ITEM (window->view_toolbar),
		 window->toolBarOn ?
		 eel_gconf_get_boolean (CONF_WINDOWS_SHOW_TOOLBARS) :
		 FALSE);
	gtk_check_menu_item_set_active 
		(GTK_CHECK_MENU_ITEM (window->view_bookmarks),
		 window->toolBarOn ?
		 eel_gconf_get_boolean (CONF_WINDOWS_SHOW_BOOKMARKS) :
		 FALSE);
	gtk_check_menu_item_set_active 
		(GTK_CHECK_MENU_ITEM (window->view_statusbar),
		 window->statusBarOn ?
		 eel_gconf_get_boolean (CONF_WINDOWS_SHOW_STATUSBAR) :
		 FALSE);

	/* connect state-changed on the econding menuitem to catch the
	 * first entry and create the submenu, not using entry-notify-event
	 * because of a gtk+ bug */
	gtk_signal_connect (GTK_OBJECT (window->encoding), "state-changed",
			    GTK_SIGNAL_FUNC 
			    (window_menu_encoding_state_changed_cb),
			    window);
	/* also create a dummy submenu sa that the submenu arrow is shown */
	gtk_menu_item_set_submenu (GTK_MENU_ITEM (window->encoding), 
				   gtk_menu_new ());
	gtk_menu_item_set_submenu (GTK_MENU_ITEM (window->csslist),
				   gtk_menu_new ());

	/* handle expose for the edit menu, used to set the edit menuitems 
	 * sensitivity according to the current selection */
	gtk_signal_connect (GTK_OBJECT (window->edit_cut->parent), 
			    "expose_event",
			    GTK_SIGNAL_FUNC (window_menu_edit_expose_event_cb),
			    window);

#ifdef ENABLE_EXPERIMENTAL_FILTERS
	/* FIXME fix this one up to work nicely with the filters*/
	gtk_widget_hide (window->allow_popups);
#endif

	/* setup view menu and install notifiers*/
	window_menubar_init_notifiers (window);
}

static void
window_toolbars_create (GaleonWindow *window)
{
	/* create the toolbars */
	toolbar_create (window, TRUE);
	bookmarks_toolbars_create (window);
}

void window_grab_location_focus (GaleonWindow *window)
{
	if (window->location_entry)
	{
		gtk_widget_grab_focus (
			GTK_WIDGET (window->location_entry));
	}
}

void
window_save_layout (GaleonWindow *window)
{
	g_return_if_fail (window->layout == NULL);

	/* get the saved layout string and store it in the window structure */
	window->layout = gnome_config_get_string ("/galeon/Placement/Dock");

	/* make sure there's a layout to build into */
	if (GNOME_APP (window->WMain)->layout == NULL)
	{
		GNOME_APP (window->WMain)->layout = gnome_dock_layout_new ();
	}
}

void
window_restore_layout (GaleonWindow *window)
{
	GnomeApp *app;
	GList *lp;
	
	/* get the app */
	app = GNOME_APP (window->WMain);

	/* restore placements of recreated items */
	/* have to do this manually to get the ordering right, since
	 * we don't want to disturb things which we haven't recreated,
	 * such as the menu bar */
	gnome_dock_layout_parse_string (app->layout, window->layout);
	for (lp = app->layout->items; lp != NULL; lp = g_list_next (lp))
	{
		GnomeDockLayoutItem *item = (GnomeDockLayoutItem *)(lp->data);
		
		if (item->placement == GNOME_DOCK_FLOATING)
		{
			gnome_dock_add_floating_item
				(GNOME_DOCK (app->dock),
				 item->item,
				 item->position.floating.x,
				 item->position.floating.y,
				 item->position.floating.orientation);
		}
		else
		{
			gnome_dock_add_item
				(GNOME_DOCK (app->dock),
				 item->item,
				 item->placement,
				 item->position.docked.band_num,
				 0,
				 item->position.docked.offset,
				 TRUE);
		}
	}

	/* get rid of the layout object, it's no longer needed */
	gtk_object_unref (GTK_OBJECT (app->layout));
	app->layout = NULL;

	/* free the layout string */
	g_free (window->layout);
	window->layout = NULL;
}

static void
window_statusbar_create (GaleonWindow *window)
{
	gnome_app_set_statusbar (
		GNOME_APP(window->WMain),
		gnome_appbar_new (TRUE, TRUE,
				  GNOME_PREFERENCES_NEVER));
	window->appbar = GNOME_APP(window->WMain)->statusbar;

	window->security_frame = gtk_frame_new(NULL);
	gtk_frame_set_shadow_type(GTK_FRAME(window->security_frame), 
				  GTK_SHADOW_IN);

	window_statusbar_set_security_icon (window, FALSE);

	gtk_box_pack_start(GTK_BOX(window->appbar), 
			   GTK_WIDGET(window->security_frame), 
			   FALSE, TRUE, 0);
	gtk_widget_show(window->security_frame);
}

void
window_statusbar_set_security_icon (GaleonWindow *window, gboolean state)
{
	PixmapData *pixmap = NULL;
	return_if_not_window (window);
	
	if (!state)
		pixmap = get_theme_pixmap ("insecure.xpm", FALSE);
	else
		pixmap = get_theme_pixmap ("secure.xpm", FALSE);


	if (!window->security_icon)
	{

	  	window->security_icon = gtk_pixmap_new (pixmap->pixmap,
						        pixmap->mask);
		gtk_container_add (GTK_CONTAINER(window->security_frame), 
				   GTK_WIDGET(window->security_icon));
		gtk_widget_show (window->security_icon);
	}
	else
	{
		gtk_pixmap_set (GTK_PIXMAP (window->security_icon),
				pixmap->pixmap, pixmap->mask);
	}
}

static void
window_set_selection_signals (GaleonWindow *window)
{
        /* set selection signal */
	gtk_selection_add_targets (GTK_WIDGET(window->WMain),
				   GDK_SELECTION_PRIMARY, 
				   selection_types, 
				   selection_types_num_targets);
	gtk_selection_add_targets (GTK_WIDGET(window->WMain),
				   gdk_atom_intern("CLIPBOARD", FALSE),
				   selection_types, 
				   selection_types_num_targets);
	gtk_signal_connect (GTK_OBJECT(window->WMain), "selection_received",
			    GTK_SIGNAL_FUNC (window_selection_received_cb),
			    window);
	gtk_signal_connect (GTK_OBJECT(window->WMain), "selection_get",
			    GTK_SIGNAL_FUNC (window_selection_get_cb),
			    NULL);
}

static void
window_create_embed_container (GaleonWindow *window)
{
	/* make the toplevel notebobok */
	window->notebook = gtk_notebook_new ();

	/* set some notebook properties */
	gtk_notebook_set_tab_hborder (GTK_NOTEBOOK (window->notebook), 0);
	gtk_notebook_set_tab_vborder (GTK_NOTEBOOK (window->notebook), 0);
	gtk_notebook_popup_enable (GTK_NOTEBOOK (window->notebook));
	gtk_notebook_set_scrollable (GTK_NOTEBOOK (window->notebook), TRUE);
	gtk_signal_connect_after (GTK_OBJECT (window->notebook), "switch_page",
				  window_notebook_switch_page_cb, window);
	gtk_signal_connect_after (GTK_OBJECT (window->notebook), "add",
				  window_notebook_add_remove_page_cb, window);
	gtk_signal_connect_after (GTK_OBJECT (window->notebook), "remove",
				  window_notebook_add_remove_page_cb, window);

	/* connect signals for tab drag events */
	gtk_widget_add_events (window->notebook, GDK_BUTTON1_MOTION_MASK |
			       GDK_LEAVE_NOTIFY_MASK);
	gtk_signal_connect_after (GTK_OBJECT (window->notebook),
				  "button_press_event", GTK_SIGNAL_FUNC
				  (window_notebook_button_press_cb), window);
	gtk_signal_connect (GTK_OBJECT (window->notebook),
			    "button_release_event", GTK_SIGNAL_FUNC
			    (window_notebook_button_release_cb), window);
			    
	gtk_notebook_set_tab_pos (GTK_NOTEBOOK (window->notebook),
				  eel_gconf_get_integer 
				  (CONF_TABS_TABBED_POSITION));
	gtk_notebook_set_show_border (GTK_NOTEBOOK (window->notebook), FALSE);
	gtk_widget_show (GTK_WIDGET (window->notebook));

	/* make the toplevel hpaned, for docks */
	window->hpaned = gtk_hpaned_new ();
	gtk_paned_set_gutter_size (GTK_PANED (window->hpaned), 12);
	gtk_paned_set_handle_size (GTK_PANED (window->hpaned), 10);

	/* make a toplevel hbox for inserting the paned into */
	window->hbox = gtk_hbox_new (FALSE, 0);
	gtk_box_pack_start (GTK_BOX (window->hbox),
			    GTK_WIDGET (window->hpaned),
			    TRUE, TRUE, 0);
	gtk_box_pack_end (GTK_BOX (window->hbox),
			  GTK_WIDGET (window->notebook),
			  TRUE, TRUE, 0);

	/* insert hbox into toplevel window */
	gnome_app_set_contents (GNOME_APP (window->WMain), 
				GTK_WIDGET (window->hbox));
}

static void
window_set_chrome (GaleonWindow *window, guint32 chrome_mask)
{
	/* set the chrome info */
	window->menuBarOn = FALSE;
	window->toolBarOn = FALSE;
	window->locationBarOn = FALSE;
	window->statusBarOn = FALSE;

	if (chrome_mask & GTK_MOZ_EMBED_FLAG_MENUBARON)
	{
		window->menuBarOn = TRUE;
	}
	if (chrome_mask & GTK_MOZ_EMBED_FLAG_TOOLBARON)
	{
		window->toolBarOn = TRUE;
	}
	if (chrome_mask & GTK_MOZ_EMBED_FLAG_LOCATIONBARON)
	{
		window->locationBarOn = TRUE;
	}
	if (chrome_mask & GTK_MOZ_EMBED_FLAG_STATUSBARON)
	{
		window->statusBarOn = TRUE;
	}
}

/**
 * window_update_statusbar: update the status bar of the toplevel window
 */
void
window_update_statusbar (GaleonWindow *window)
{
	GaleonEmbed *embed;
	GtkWidget *progress;
	const gchar *status;
	gchar message[256];

	return_if_not_window (window);
	embed = window->active_embed;

	/* this may be called before any embed is activate */
	if (embed == NULL)
	{
		return;
	}

	/* still check the magic number */
	return_if_not_embed (embed);

	/* get progress bar widget */
	progress = GTK_WIDGET (gnome_appbar_get_progress 
			       (GNOME_APPBAR(window->appbar)));

	/* have we started loading? */
	if (embed->load_started > 0 && embed->bytesLoaded > 0)
	{
		if (embed->loadPercent == 0) 
		{
			/* not really, go into activity mode */
			gtk_progress_set_activity_mode 
				(GTK_PROGRESS (progress), TRUE);
			if (!(window->progress_timeout))
			{
				window->progress_timeout = TRUE;
				g_timeout_add (100, (GSourceFunc)
					       window_progress_action, 
					       window);
			}
		} 
		else
		{
			/* yes, show the progress in progress bar */
			window->progress_timeout = FALSE;
			gtk_progress_set_activity_mode 
				(GTK_PROGRESS (progress), FALSE);
			gnome_appbar_set_progress 
				(GNOME_APPBAR (window->appbar), 
				 embed->loadPercent / 100.0);
		}
	}
	else
	{
		/* go to sleep */
		window->progress_timeout = FALSE;
		gtk_progress_set_activity_mode (GTK_PROGRESS (progress),
						FALSE);
		gnome_appbar_set_progress (GNOME_APPBAR (window->appbar), 0);
	}

	/* get rid of last message */
	gnome_appbar_pop (GNOME_APPBAR (window->appbar));

	/* temporary message takes priority */
	if (window->tempMessage != NULL && (strlen (window->tempMessage) != 0))
	{
		gnome_appbar_push (GNOME_APPBAR (window->appbar),
				   window->tempMessage);
		return;
	}

	/* get a status message */
	status = (embed->statusMessage == NULL ? "" : embed->statusMessage);

	/* make a progress message */
	if (embed->bytesLoaded == 0)
	{
		g_snprintf (message, 255, "%s", status);
	}
	else if (embed->bytesLoaded <= embed->maxBytesLoaded)
	{
		gchar time_remaining[64] = "";
		gint hours, minutes, seconds;
		GTime time_delta;

		/* try to compute roughly the time remaining for the load */
		time_delta = (time (NULL) - embed->when_started);
		if (embed->loadPercent > 5 && 
		    embed->loadPercent < 100 && time_delta > 0)
		{
			time_delta *= ((double)embed->maxBytesLoaded / 
				       (double)embed->bytesLoaded) - 1.0;
			hours = time_delta / (60 * 60);
			time_delta %= (60 * 60);
			minutes = time_delta / 60;
			seconds = time_delta % 60;
			snprintf (time_remaining, 64,
				  _(", %02d:%02d:%02d remaining"),
				  hours, minutes, seconds);
		}
		
		/* fill the status bar text with progress info */
		g_snprintf (message, 255, 
			    _("%s (%d%% complete, %d kB of %d kB loaded%s)"),
			    status, 
			    embed->loadPercent, 
			    embed->bytesLoaded / 1024,
			    embed->maxBytesLoaded / 1024,
			    time_remaining);
	}
	else
	{
		/* fill the status bar text with progress info: only kb */
		g_snprintf (message, 255, _("%s (%d kB loaded)"), 
			    status, 
			    embed->bytesLoaded / 1024);
	}

	/* show the new message */
	gnome_appbar_push (GNOME_APPBAR (window->appbar), message);
}

/**
 * window_update_temp_message: update the temporary message
 */
void
window_update_temp_message(GaleonWindow *window, const char *message)
{
	/* free the previous message */
	if (window->tempMessage) 
	{
		g_free(window->tempMessage);
	}
	
	/* fill the new temporary message */
	if (message != NULL) 
	{
		char *tmp;

		window->tempMessage = g_strdup (message);

		/* remove \n or the statusbar
		   height will grow */
		tmp = window->tempMessage;
		while (*tmp != '\0')
		{
			if (*tmp == '\n')
			{
				*tmp = ' ';
			}
			tmp ++;
		}
	}	
	else
	{	
		window->tempMessage = NULL;
	}
	window_update_statusbar (window);
}

/**
 * window_update_tab_controls: updates the various tab-related items inside
 * of the "View" menu
 */
void
window_update_tab_controls (GaleonWindow *window)
{
	gboolean tabs_to_left, tabs_to_right;
	gboolean tabs, show_tabs;
	GaleonEmbed *embed;
	gint index, size;

	return_if_not_window (window);

	/* get active embed */
	embed = window->active_embed;
	return_if_not_embed (embed);

	/* set next/prev tab and shift tab menuitems */
	index = gtk_notebook_page_num (GTK_NOTEBOOK (window->notebook), 
				       GTK_WIDGET (embed->mozEmbed));
	size = g_list_length (GTK_NOTEBOOK (window->notebook)->children);
	tabs = (size > 1);
	tabs_to_left = (index > 0);
	tabs_to_right = (index < (size - 1));

	gtk_widget_set_sensitive (window->detach_tab, tabs);
	gtk_widget_set_sensitive (window->prev_tab, tabs);
	gtk_widget_set_sensitive (window->next_tab, tabs);
	gtk_widget_set_sensitive (window->move_tab_left, tabs_to_left);
	gtk_widget_set_sensitive (window->move_tab_right, tabs_to_right);

	/* update tab display */
	show_tabs = eel_gconf_get_boolean (CONF_TABS_TABBED_ALWAYS_SHOW);
	gtk_notebook_set_show_tabs (GTK_NOTEBOOK (window->notebook),
				    (show_tabs && !window->is_popup) ||
				    (size > 1));
}

/**
 * window_update_nav_controls: update back and forward toolbar buttons
 * status and status of items in go menu
 */
void
window_update_nav_controls (GaleonWindow *window)
{
	gboolean can_go_back;
	gboolean can_go_up;
	gboolean can_go_forward;
	gboolean can_stop;
	gint tearoff = 0;
	GaleonEmbed *embed;
	GtkWidget *menu;
	GList *children;

	return_if_not_window (window);

	/* get active embed */
	embed = window->active_embed;
	return_if_not_embed (embed);
		
	/* query mozilla / embed */
	can_go_back =
		gtk_moz_embed_can_go_back (GTK_MOZ_EMBED(embed->mozEmbed));
	can_go_up = embed_can_go_up (embed);
	can_go_forward =
		gtk_moz_embed_can_go_forward (GTK_MOZ_EMBED(embed->mozEmbed));
	can_stop = (embed->load_started > 0);

	/* gets gnome detachabilty of menus so we set sensitivity on
	   the right item */
	if (gnome_preferences_get_menus_have_tearoff ())
	{
		tearoff++;
	}
		
	/* get the go_menu widgets */
	menu = window->go_menu;
	children = gtk_container_children (GTK_CONTAINER(menu));
		
	/* set go_menu buttons */
	gtk_widget_set_sensitive (
		GTK_WIDGET(g_list_nth_data(children, 0 + tearoff)),
		can_go_back);
	gtk_widget_set_sensitive (
		GTK_WIDGET(g_list_nth_data(children, 1 + tearoff)),
		can_go_forward);
	gtk_widget_set_sensitive (
		GTK_WIDGET(g_list_nth_data(children, 2 + tearoff)),
		can_go_up);
	gtk_widget_set_sensitive (
		GTK_WIDGET(g_list_nth_data(children, 5 + tearoff)),
		can_stop);

	/* free the list of children */
	g_list_free (children);

	/* update back, forward, up, stop and refresh buttons */
	if (window->back_button != NULL)
	{
		gtk_widget_set_sensitive 
			(window->back_button, can_go_back);
	}
	if (window->back_history_button != NULL)
	{
		gtk_widget_set_sensitive 
			(window->back_history_button, can_go_back);
	}
	if (window->up_button != NULL)
	{
		gtk_widget_set_sensitive
			(window->up_button, can_go_up);
	}
	if (window->forward_button != NULL)
	{
		gtk_widget_set_sensitive
			(window->forward_button, can_go_forward);
	}
	if (window->forward_history_button != NULL)
	{
		gtk_widget_set_sensitive
			(window->forward_history_button, 
			 can_go_forward);
	}
	if (window->stop_button != NULL)
	{
		gtk_widget_set_sensitive 
			(window->stop_button, can_stop);
	}
}

/**
 * window_update_zoom: update the zoom spin control
 */
void
window_update_zoom (GaleonWindow *window)
{
	if (window->zoom_spin != NULL && window->active_embed != NULL)
	{
		gtk_spin_button_set_value 
			(GTK_SPIN_BUTTON (window->zoom_spin),
			 (gfloat)(window->active_embed->zoom));
	}
}

/**
 * window_show_open_dialog: show the open dialog
 */
void window_show_open_dialog (GaleonWindow *window)
{
	gchar *dir, *retDir;
	gchar *file = NULL;
	GnomeVFSURI *uri;

	dir = eel_gconf_get_string (CONF_STATE_OPEN_DIR);

	if (show_file_picker (window->WMain, _("Select the file to open:"),
			      dir, NULL, modeOpen,
			      &file, NULL))
	{
		uri = gnome_vfs_uri_new (file);
		if (uri)
		{
			window_load_url(window, file);

			retDir = gnome_vfs_uri_extract_dirname (uri);

			/* set default open dir */
			eel_gconf_set_string (CONF_STATE_OPEN_DIR, 
						 retDir);

			g_free (retDir);
			gnome_vfs_uri_unref (uri);
		}


	}

	g_free (dir);	
	g_free (file);	
}

/**
 * window_show_openurl_dialog: show the open url dialog
 */
void window_show_openurl_dialog (GaleonWindow *window)
{
	GladeXML *gxml;
	GtkWidget *dialog = NULL;
	GtkWidget *entry;
	extern gchar *open_url_str;

	gxml = glade_widget_new ("galeon.glade", "open_url_dialog", 
				 &dialog, window);
	entry = glade_xml_get_widget (gxml, "open_url_entry");

	g_return_if_fail (dialog != NULL);
	g_return_if_fail (entry != NULL);

	/* unref the xml object - we don't need it any more */
	gtk_object_unref (GTK_OBJECT (gxml));

	/* this is done so that the enter key is not captured by the entry */
	gnome_dialog_editable_enters (GNOME_DIALOG (dialog),
				      GTK_EDITABLE (entry));

	/* FIXME: is this really desirable? */
	if (open_url_str)
	{
		gtk_entry_set_text (GTK_ENTRY (entry), open_url_str);
	}

	window->open_url_entry = entry;
	dialog_set_parent (dialog, window->WMain);
}

/**
 * window_toolbar_show: show the toolbar
 */
void window_toolbar_show (GaleonWindow *window)
{
	gtk_widget_show (window->main_dockitem);	
	if (!eel_gconf_get_boolean (CONF_TOOLBAR_URL_LOCATION))
	{
		gtk_widget_show (window->location_dockitem);
	}

	if (!GTK_CHECK_MENU_ITEM(window->view_fullscreen)->active)
		window->show_toolbar = TRUE;
}

/**
 * window_toolbar_hide: hide the toolbar
 */
void window_toolbar_hide (GaleonWindow *window)
{
	gtk_widget_hide (GTK_WIDGET (window->main_dockitem));
	if (window->location_dockitem)
	{
		gtk_widget_hide (GTK_WIDGET (window->location_dockitem));
	}
	gtk_widget_queue_resize (GTK_WIDGET (window->hbox));

	if (!GTK_CHECK_MENU_ITEM(window->view_fullscreen)->active)
		window->show_toolbar = FALSE;
}

/**
 * window_menubar_show: show the menubar
 */
void window_menubar_show (GaleonWindow *window)
{
	gtk_widget_show (GTK_WIDGET (window->menubar->parent));	

	if (!GTK_CHECK_MENU_ITEM(window->view_fullscreen)->active)
		window->show_menubar = TRUE;
}

/**
 * window_menubar_hide: hide the menubar
 */
void window_menubar_hide (GaleonWindow *window)
{
	gtk_widget_hide (GTK_WIDGET (window->menubar->parent));
	gtk_widget_queue_resize (GTK_WIDGET (window->hbox));

	if (!GTK_CHECK_MENU_ITEM(window->view_fullscreen)->active)
		window->show_menubar = FALSE;
}

/**
 * window_statusbar_show: show the statusbar
 */
void window_statusbar_show (GaleonWindow *window)
{
	gtk_widget_show (GTK_WIDGET (window->appbar->parent));

	if (!GTK_CHECK_MENU_ITEM(window->view_fullscreen)->active)
		window->show_statusbar = TRUE;
}

/**
 * window_statusbar_hide: hide the statusbar
 */
void window_statusbar_hide (GaleonWindow *window)
{
	gtk_widget_hide (window->appbar->parent);
	gtk_widget_queue_resize (GTK_WIDGET (window->hbox));

	if (!GTK_CHECK_MENU_ITEM(window->view_fullscreen)->active)
		window->show_statusbar = FALSE;
}

/**
 * window_close: close a GaleonWindow
 */
void 
window_close (GaleonWindow *window)
{
	GList *copy;

	return_if_not_window (window);

	/* hide the window, this makes the app seem more responsive */
	gtk_widget_hide (window->WMain);

	/* close any dock (in order to store width of dock) */
	window_undock (window);

	/* save window size if we are not in fullscreen and if 
	 * the window is not a popup */
	if (!window->is_popup &&
	    !GTK_CHECK_MENU_ITEM (window->view_fullscreen)->active)
	{	
		eel_gconf_set_integer(CONF_STATE_WINWIDTH, 
				     window->WMain->allocation.width);
		eel_gconf_set_integer(CONF_STATE_WINHEIGHT, 
				     window->WMain->allocation.height);
	}

	/* free any temporary message */
	if (window->tempMessage != NULL)
	{
		g_free (window->tempMessage);
		window->tempMessage = NULL;
	}

	/* stop the spinner if it exists; I'm not sure if this is essential
	 * but it's an attempt to workaround GnomeAnimator crashes -- MattA */
	if (window->spinner != NULL)
        {
		spinner_destroy (window);
        }

	/* kill off find dialog if active */
	if (window->find_dialog != NULL)
	{
		find_destroy_dialog (window);
	}

	/* destroy tooltips */
	if (window->bookmarks_tooltips)
	{
		gtk_object_destroy (GTK_OBJECT (window->bookmarks_tooltips));
		window->bookmarks_tooltips = NULL;
	}

	/* remove notifiers */
	if (window->notifiers_id != NULL);
	{
		galeon_notification_remove(&window->notifiers_id);
	}

	/* unconnect the notebook motion and leave signals */
	if (window->drag_motion_signal)
	{
		gtk_signal_disconnect (GTK_OBJECT (window->notebook),
				       window->drag_motion_signal);
		gtk_signal_disconnect (GTK_OBJECT (window->notebook),
				       window->drag_leave_signal);
	}

	/* ungrab pointer if we're in a tab drag */
	if (window->in_drag)
	{
		gdk_pointer_ungrab (GDK_CURRENT_TIME);
		gtk_grab_remove (window->notebook);
	}

	/* any children? */
	if (window->embed_list != NULL)
	{
		/* close any embed children */
		copy = g_list_copy (window->embed_list);
		g_list_foreach (copy, (GFunc)embed_close, NULL);
		g_list_free (copy);

		/* window_close will now be called again automatically */
	}
	else
	{
		/* stop the activity bar */
		window->progress_timeout = FALSE;

		/* destroy the window, and all it contains */
		gtk_widget_destroy (window->WMain);
		window->WMain = NULL;

		/* remove window from session */
		session_remove_window (window);

		/* destroy dummy widgets list */
		g_list_foreach (window->dummy_widgets, 
				(GFunc)gtk_widget_unref, NULL);
		g_list_free (window->dummy_widgets);
		
		/* scrub and free the window structure */
		memset (window, 0, sizeof (GaleonWindow));
		g_free (window);
	}
}

/**
 * window_go_home:
 */
void
window_go_home (GaleonWindow *window, LinkState state)
{
	gchar *startpage;

	startpage = eel_gconf_get_string 
		(CONF_GENERAL_HOMEPAGE);

        if (startpage != NULL && strlen(startpage) != 0)
        {
		embed_activate_link (window->active_embed, NULL, 
				     startpage, state);
		g_free(startpage);
	}
        else
	{
		gnome_error_dialog (_("Please specify a Home Page "
				      "in the Preferences dialog."));
	}
}

/**
 * window_set_layer: make sure the window is on the right layer. Don't
 * use this for dialogs any more; instead use dialog_set_parent.
 */
void
window_set_layer (GaleonWindow *window)
{
	/* fullscreen mode flag */
	extern gboolean fullscreen_active;

	/* check if we're in fullscreen mode and stacked above dock */
	if (fullscreen_active && 
	    eel_gconf_get_boolean (CONF_WINDOWS_FULLSCREEN_STACKING))
	{
		/* get to the top */
		gnome_win_hints_set_layer (window->WMain, 
					   WIN_LAYER_ABOVE_DOCK);
	}
	else
	{
		/* down boy! */
		gnome_win_hints_set_layer (window->WMain, WIN_LAYER_NORMAL);
	}

	/* make sure it's raised */
	gdk_window_raise (window->WMain->window);

	window->layered = TRUE;
}

void
window_toggle_fullscreen_mode (GaleonWindow *window)
{
	window_set_fullscreen_mode (window, !fullscreen_active);
}

void
window_set_fullscreen_mode (GaleonWindow *window, gboolean active)
{
	GdkWindow *gdk_window;

	return_if_not_window (window);

	GTK_CHECK_MENU_ITEM (window->view_fullscreen)->active = active;

	if (active)
	{
		gboolean bool;

		bool = eel_gconf_get_boolean
			(CONF_WINDOWS_FS_SHOW_MENUBAR);
		if (bool != window->show_menubar) 
 		{
 			gtk_check_menu_item_set_active
 				(GTK_CHECK_MENU_ITEM
				 (window->view_menubar),
				 bool);
 		}
		bool = eel_gconf_get_boolean
			(CONF_WINDOWS_FS_SHOW_TOOLBARS);
		if (bool != window->show_toolbar) 
 		{
 			gtk_check_menu_item_set_active
 				(GTK_CHECK_MENU_ITEM
				 (window->view_toolbar),
				 bool);
 		}
		bool = eel_gconf_get_boolean
			(CONF_WINDOWS_FS_SHOW_BOOKMARKS);
		if (bool != window->show_bookmarks) 
 		{
			gtk_check_menu_item_set_active
 				(GTK_CHECK_MENU_ITEM
				 (window->view_bookmarks),
				 bool);
 		}
		bool = eel_gconf_get_boolean
			(CONF_WINDOWS_FS_SHOW_STATUSBAR);
		if (bool != window->show_statusbar)
 		{
 			gtk_check_menu_item_set_active
 				(GTK_CHECK_MENU_ITEM
				 (window->view_statusbar),
				 bool);
 		}
	}
	else
	{
		/* set things back to the state they were before 
		 * fullscreen */
		gtk_check_menu_item_set_active
			(GTK_CHECK_MENU_ITEM (window->view_menubar),
			 window->show_menubar);
		gtk_check_menu_item_set_active
			(GTK_CHECK_MENU_ITEM (window->view_toolbar),
			 window->show_toolbar);
		gtk_check_menu_item_set_active
			(GTK_CHECK_MENU_ITEM (window->view_bookmarks),
			 window->show_bookmarks);
		gtk_check_menu_item_set_active
			(GTK_CHECK_MENU_ITEM (window->view_statusbar),
			 window->show_statusbar);
	}

	fullscreen_active = active;
	gdk_window = window->WMain->window;
	window_set_layer (window);

	if (active)
	{
		gint client_x, client_y, root_x, root_y;
		gint width, height;
		gint screen_width, screen_height;

		/* get window position and geometry */
		gdk_window_get_origin (gdk_window, &root_x, &root_y);
		gdk_window_get_geometry (gdk_window, &client_x, &client_y,
					 &width, &height, NULL);

		/* store original position and size */
		window->x = root_x - client_x;
		window->y = root_y - client_y;
		window->width = width;
		window->height = height;

		/* get the size of the screen */
		screen_width = gdk_screen_width ();
		screen_height = gdk_screen_height ();

#ifdef HAVE_XINERAMA
		/* if the user is using Xinerama, adjust the area and
		 * positioning of the fullscreen window so it's not
		 * occupying any dead area or covering all of the heads */
		{
		Display *dpy;

		dpy = GDK_DISPLAY ();
#ifdef __sgi
		if (XineramaActive (dpy,0))
#else
		if (XineramaIsActive (dpy))
#endif		
		{
			int num_heads, i;
			int max_area = 0, max_area_head = 0;
			int int_width, int_height, int_area;
#ifdef __sgi
			XRectangle *head_info;		
			XineramaGetInfo(dpy, 0, &head_info, &num_heads);
#else
			XineramaScreenInfo *head_info;

			/* query heads */
			head_info = XineramaQueryScreens (dpy, &num_heads);
#endif			
			g_return_if_fail (num_heads != 0);

			/* find the head with the largest area of the
			 * window in it */
			for (i = 0; i < num_heads; i++)
			{
				/* find the width and height of the
				 * intersecting area */
#ifdef __sgi				 
				int_width = MIN (head_info[i].x +
					head_info[i].width,
					window->x + window->width) -
					MAX (head_info[i].x, window->x);
				int_height = MIN (head_info[i].y +
					head_info[i].height,
					window->y + window->height) -
					MAX (head_info[i].y, window->y);
#else
				int_width = MIN (head_info[i].x_org +
					head_info[i].width,
					window->x + window->width) -
					MAX (head_info[i].x_org, window->x);
				int_height = MIN (head_info[i].y_org +
					head_info[i].height,
					window->y + window->height) -
					MAX (head_info[i].y_org, window->y);
#endif
				/* find the area of the intersection */
				if (int_width < 0 || int_height < 0)
					int_area = 0;
				else
					int_area = int_width * int_height;

				/* see if this head has a larger area */
				if (int_area > max_area)
				{
					max_area_head = i;
					max_area = int_area;
				}
			}

			/* update screen size and position offset */
			screen_width = head_info[max_area_head].width;
			screen_height = head_info[max_area_head].height;
#ifdef __sgi			
			client_x -= head_info[max_area_head].x;
			client_y -= head_info[max_area_head].y;
#else			
			client_x -= head_info[max_area_head].x_org;
			client_y -= head_info[max_area_head].y_org;
#endif			
			XFree (head_info);
		}
		}
#endif

		/* move and resize the window (+1s are to get rid of the
		 * crappy one-pixel-border along the right edge and bottom
		 * that makes it hard to hit the scroll buttons) */
		gdk_window_move_resize (gdk_window, -client_x, -client_y,
					screen_width + 1, screen_height + 1);
	}
	else
	{
		/* restore the initial position and size */
		gdk_window_move_resize (gdk_window, 
					window->x, window->y,
					window->width, 
					window->height);
	}
}

static void 
window_set_menu_data (GaleonWindow *window)
{
	gint i, j;

	for (i = 0; i < num_menus; i++)
	{
		for (j = 0; j < menus_num_items[i]; j++)
		{
			all_menus[i][j].user_data = window;
		}
	}
}

/**
 * window_from_widget: get the GaleonWindow structure associated with
 * a widget within a main browser window. This is necessary in a few of
 * the tricker callbacks, and simply finds the WMain (by tracing up the
 * widget heirarchy), and the does an object data lookup.
 */
GaleonWindow *
window_from_widget (GtkWidget *widget)
{
	GaleonWindow *found_window = NULL;

	/* check */
	g_return_val_if_fail (widget != NULL, NULL);

	/* do the search */
	while (widget)
	{
		/* do the lookup */
		found_window = gtk_object_get_data (GTK_OBJECT (widget),
						    "GaleonWindow");

		/* get out if success */
		if (found_window != NULL)
		{
			break;
		}

		/* find parent */
		widget = (GTK_IS_MENU (widget) ? 
			  (gtk_menu_get_attach_widget (GTK_MENU (widget))) :
			  (widget->parent));
	}

	/* check -- FIXME: turn this critical */
	if (found_window == NULL)
	{
		g_warning ("GaleonWindow not found on widget");
	}

	/* return success */
	return found_window;
}

/**
 * window_reload_all: reload all tabs in a window
 */
void
window_reload_all (GaleonWindow *window)
{
	GList *l;

	/* check arguments */
	return_if_not_window (window);

	/* reload all tabs in the window */
	for (l = window->embed_list; l != NULL; l = g_list_next (l))
	{
		embed_reload ((GaleonEmbed *)(l->data), 
			      GTK_MOZ_EMBED_FLAG_RELOADNORMAL);
	}
}

/**
 * window_undock: remove the current dock
 */
void
window_undock (GaleonWindow *window)
{
	/* check something is docked */
	if (window->docked == NULL)
	{
		return;
	}

	/* store width in pref */
	if (window->docked_width_pref != NULL && 
	    GTK_PANED (window->hpaned)->position_set)
	{
	  eel_gconf_set_integer (window->docked_width_pref,
				 GTK_PANED (window->hpaned)->child1_size);
	}

	/* hide the hpaned and notebook */
	gtk_widget_hide (GTK_WIDGET (window->hpaned));
	gtk_widget_hide (GTK_WIDGET (window->notebook));
 
	/* remove the notebook from the hpaned and insert it into the box */
	gtk_widget_reparent (GTK_WIDGET (window->notebook),
			     GTK_WIDGET (window->hbox));

        /* destroy the docked widget */
	gtk_widget_destroy (GTK_WIDGET (window->docked));
	window->docked = NULL;

	/* update toolbar buttons */
	window_update_bm_and_hist_buttons (window, FALSE, FALSE);

	/* set dock type */
	window->dock_type = DOCK_NONE;
	
	/* show the notebook again */
	gtk_widget_show (GTK_WIDGET (window->notebook));
}

/**
 * window_dock: dock a widget into a window, destroying anything
 * that was there previously.
 */
void
window_dock (GaleonWindow *window, GtkWidget *widget, const gchar *width_pref)
{
	gint width;

	/* hide the notebook */
	gtk_widget_hide (GTK_WIDGET (window->notebook));

	/* destroy current dock */
	if (window->docked != NULL)
	{
		window_undock (window);
	}

	/* dock this */
	gtk_paned_add1 (GTK_PANED (window->hpaned), GTK_WIDGET (widget));
	window->docked = widget;
	window->docked_width_pref = width_pref;

	/* show the paned view */
	/* NB: this must be done before setting pane position! */
	gtk_widget_show (GTK_WIDGET (window->hpaned));

	/* move pane to accomodate width */
	if (width_pref != NULL)
	{
		width = eel_gconf_get_integer (width_pref);
		if (width != -1)
		{
			gtk_paned_set_position (GTK_PANED (window->hpaned),
						width);
		}
	}

	/* move notebook into the other side of the paned */
	gtk_widget_reparent (GTK_WIDGET (window->notebook),
			     GTK_WIDGET (window->hpaned));

	/* show the notebook again */
	gtk_widget_show (GTK_WIDGET (window->notebook));
}

/*
 * create the charset titles submenu structure 
 */
void
window_create_charset_submenus (GaleonWindow *window,
				GList *charset_titles)
{
	GtkWidget *encoding_menu, *tw, *tw2 = NULL, *tw3;
	GList *tl, *tl2 = NULL;
	gint i, j;
	gint lgroups_count = get_lgroups_count ();
	gint translated_cscount = get_translated_cscount ();
	
 	encoding_menu = gtk_menu_new();
	gtk_menu_item_set_submenu (GTK_MENU_ITEM (window->encoding), 
				   encoding_menu);

	tl = g_list_copy(charset_titles);
	
	for (i = 0;i < lgroups_count;i++) {
		tw = gtk_menu_item_new_with_label (_(lgroups[i]));
		gtk_menu_append (GTK_MENU(encoding_menu), tw);
		gtk_widget_lock_accelerators (tw);
		gtk_widget_show (tw);
		
		tw2 = gtk_menu_new();
		gtk_menu_item_set_submenu (GTK_MENU_ITEM (tw), tw2);
		
		for (j = 0; j < translated_cscount; j++)
			if (charset_trans_array[j].lgroup == i) {
				tl2 = g_list_find_custom (
					tl, 
					_(charset_trans_array[j].charset_title),
					strcasestr_cb);
				if (tl2 != NULL) {
					tl = g_list_remove_link (tl, tl2);
					g_list_free_1 (tl2);
				} 
				else /* we dont want to add menuitems for
				      * charset titles not in mozilla */
					continue;
				
				tw3 = gtk_menu_item_new_with_label (
				       _(charset_trans_array[j].charset_title));
				gtk_menu_append (GTK_MENU (tw2), tw3);
				gtk_widget_lock_accelerators (tw3);
				gtk_widget_show (tw3);
				gtk_signal_connect (
					GTK_OBJECT (tw3), 
					"activate",
					window_menu_encoding_activate_cb, 
					window);
			}
	}
	/* add the leftovers /if any/ to the Other submenu */
	while (tl != NULL) { 
		tw = gtk_menu_item_new_with_label (tl->data);
		gtk_menu_append (GTK_MENU(tw2), tw);
		gtk_widget_lock_accelerators (tw);
		gtk_widget_show (tw);
		gtk_signal_connect (GTK_OBJECT (tw), "activate",
				    window_menu_encoding_activate_cb, window);
		tl2 = tl->next;
		g_list_free_1 (tl);
		tl = tl2;
	}
}

static gint 
strcasestr_cb (gconstpointer a, gconstpointer b)
{
	return g_strcasestr (a, b) == NULL ? 1 : 0;
}

void
window_add_embed (GaleonWindow *window, GaleonEmbed *embed, 
		  gboolean force_jump, gboolean raise_window)
{
	gboolean auto_jump;
	GtkWidget *tab;
	gint page;

	/* set parent and store in parents list */
	embed->parent_window = window;
	window->embed_list = g_list_append (window->embed_list, embed);

	/* add as a tab into the notebook */
	tab = window_notebook_tab_new (embed, embed->site_title);
	if ((g_list_length (window->embed_list) > 1) &&
	     eel_gconf_get_boolean (CONF_TABS_TABBED_INSERT_NEW_TABS))
	{
		page = gtk_notebook_current_page 
			(GTK_NOTEBOOK (window->notebook));
		gtk_notebook_insert_page (GTK_NOTEBOOK (window->notebook),
				  	  GTK_WIDGET (embed->mozEmbed), tab,
					  page + 1);
		page++;
	}
	else
	{
		gtk_notebook_append_page (GTK_NOTEBOOK (window->notebook),
				  	  GTK_WIDGET (embed->mozEmbed), tab);
		page = gtk_notebook_page_num (GTK_NOTEBOOK (window->notebook),
					      GTK_WIDGET (embed->mozEmbed));
	}

	/* update tab-related properties of the window */
	if (window->active_embed != NULL)
	{
		window_update_tab_controls (window);
	}

	/* switch to page if necessary */
	auto_jump = eel_gconf_get_boolean (CONF_TABS_TABBED_AUTOJUMP);
	if (auto_jump || force_jump)
	{
		gtk_widget_show (embed->mozEmbed);
		gtk_notebook_set_page (GTK_NOTEBOOK (window->notebook), page);
		embed->focus_type = FOCUS_ON_CREATE;
		if (raise_window &&
		    GTK_WIDGET (window->WMain)->window != NULL)
		{
			gdk_window_raise (GTK_WIDGET (window->WMain)->window);
		}
	}
	else
	{
		embed->focus_type = FOCUS_ON_REQUEST;
	}
}

void
window_hide_one_embed (GaleonWindow *window)
{
	/* keep count */
	window->visible_embeds--;

	/* if this is the last one to be hidden, hide the main window */
	if (window->visible_embeds == 0)
	{
		gtk_widget_hide (GTK_WIDGET (window->WMain));
	}
}

void
window_show_one_embed (GaleonWindow *window)
{
	gint width, height;
	
	/* keepcount */
	window->visible_embeds++;

	/* if this isn't the first time this has been shown, skip the rest */
	if (window->visible_embeds != 1)
	{
		return;
	}

	/* find the set width and height if any */
	if (!window->set_size)
	{
                /* use system defaults */
		width = eel_gconf_get_integer (CONF_STATE_WINWIDTH);
		height = eel_gconf_get_integer (CONF_STATE_WINHEIGHT);
		gtk_window_set_default_size (GTK_WINDOW (window->WMain), 
					     width, height);
	}

	/* show it */
	gtk_widget_show (GTK_WIDGET (window->WMain));
}

static GtkWidget *
window_notebook_tab_new (GaleonEmbed *embed, const gchar *title)
{
	GtkWidget *label;
	GtkWidget *hbox;

	/* build the basic widgets */
	embed->notebook_hbox = hbox = gtk_hbox_new (FALSE, 0);
	embed->notebook_label = label = gtk_label_new (NULL);

	/* set up drag target */
	gtk_signal_connect (GTK_OBJECT (hbox), "drag_data_received",
			    GTK_SIGNAL_FUNC (embed_drag_data_received_cb),
			    embed);
	gtk_drag_dest_set (hbox, GTK_DEST_DEFAULT_ALL, embed_drop_types,
			   embed_drop_types_num_items, GDK_ACTION_COPY |
			   GDK_ACTION_MOVE | GDK_ACTION_LINK | GDK_ACTION_ASK);

	/* setup label */
	gtk_misc_set_alignment (GTK_MISC (label), 0.00, 0.5);
	gtk_misc_set_padding (GTK_MISC (label), 4, 0);
	gtk_box_pack_start (GTK_BOX (hbox), label, TRUE, TRUE, 0);

	/* set page title and add button */
	embed_update_tab_title (embed);
	embed_update_tab_close_button (embed);
	embed_update_tab_status (embed);
	embed_update_tab_size (embed);

	/* show label */
	gtk_widget_show (embed->notebook_label);

	/* return overall widget */
	return hbox;
}

void
window_session_history_menu_create (GaleonWindow *window)
{
	GList *l = session_history_get ();
	GList *li; 
	gint pos, index;
	GList *child_list;
	window_session_history_menu_remove (window);
	if (l == NULL) 
	{
		/* nothing to add */
		return;
	}
	/* look for the position to insert */
	child_list = gtk_container_children 
		(GTK_CONTAINER (window->file_menu));
	pos = 0;
	for (li = child_list; li != NULL; li = li->next)
	{
		if (li->data == window->file_session_history_separator_inf)
			break;
		pos++;
	}
	/* add the upper separator */
	window->file_session_history_separator_sup = gtk_menu_item_new ();
	gtk_widget_show_all (window->file_session_history_separator_sup);
	gtk_menu_insert (GTK_MENU (window->file_menu), 
			 window->file_session_history_separator_sup,
			 pos++);
	/* add the items */
	index = 1;
	for (li = l; li != NULL; li = li->next) 
	{
		gchar *file = li->data;
		GtkWidget *menuitem = window_session_history_menuitem 
			(file, index++);
		gtk_menu_insert (GTK_MENU (window->file_menu), 
				 menuitem,
				 pos++);
		g_free (file);
	}
	g_list_free (child_list);
	g_list_free (l);
}

static void 
window_session_history_menu_remove (GaleonWindow *window)
{
	GList *l;
	GList *li;

	if (window->file_session_history_separator_sup == NULL) 
	{
		/* nothing to remove */
		return;
	}

	l = gtk_container_children 
		(GTK_CONTAINER (window->file_menu));
	
	/* first look for the upper separator */
	for (li = l; li != NULL; li = li->next)
	{
		if (li->data == window->file_session_history_separator_sup)
		{
			break;
		}
	}
	
	/* then, destroy every widget until the 
	   other separator */
	for ( ; li != NULL; li = li->next)
	{
		if (li->data == window->file_session_history_separator_inf)
		{
			break;
		}
		if (GTK_IS_WIDGET (li->data))
		{
			gtk_widget_destroy (GTK_WIDGET (li->data));
		}
	}
	window->file_session_history_separator_sup = NULL;
	g_list_free (l);
}

static GtkWidget *
window_session_history_menuitem (gchar *file, gint index)
{
	GtkWidget *ret;
	gchar *label = g_basename (file);
	ret = gtk_menu_item_new_with_label (label);
	gtk_widget_show_all (ret);
	gtk_signal_connect (GTK_OBJECT (ret), "activate",
			    window_session_history_menuitem_activate_cb, 
			    GINT_TO_POINTER (index));
	/* FIXME: should label be freed? */
	return ret;
}

void
window_session_history_update_all (void)
{
	GList *l;
	for (l = all_windows; l != NULL; l= l->next)
		window_session_history_menu_create (l->data);
}

/**
 * window_update_bm_and_hist_buttons: update bookmarks and history togglebuttons
 * on toolbar
 */
void
window_update_bm_and_hist_buttons (GaleonWindow *window, 
				   gboolean bm, gboolean hist)
{
	if (window->bookmarks_button != NULL)
	{
		if (gtk_toggle_button_get_active
			GTK_TOGGLE_BUTTON (window->bookmarks_button) != bm)
		{
			gtk_toggle_button_set_active (
				GTK_TOGGLE_BUTTON (window->bookmarks_button),
				bm);
		}
	}
	if (window->history_button != NULL)
	{
		if (gtk_toggle_button_get_active (
			GTK_TOGGLE_BUTTON (window->history_button)) != hist)
		{
			gtk_toggle_button_set_active (
				GTK_TOGGLE_BUTTON (window->history_button),
				hist);
		}
	}
}

/*
 * window_update_ui: update user interface according to current settings
 * the hack is due to a bug in gconf: the values are correctly updated
 * only in notifiers. The bug has been already reported.
 */
void window_update_ui (void)
{
	eel_gconf_set_boolean ("/apps/galeon/updateuihack", FALSE);
}

void window_update_ui_hack (GaleonWindow *window)
{
	if (window->to_update & MAIN_TOOLBAR)
	{
		window_save_layout (window);
		toolbar_recreate (window);
		window_restore_layout (window);
	}
	if (window->to_update & BOOKMARKS_TOOLBAR)
	{
		bookmarks_tb_dirty = TRUE;
		bookmarks_updated ();
	}
	if (window->to_update & TABS_APPEAREANCE)
	{
		window_update_tabs_appearance (window);
	}

	window->to_update = 0;
}

void 
window_update_tabs_appearance (GaleonWindow *window)
{
	gint n_embeds, always_show, popup = 0;
	GList *w, *e;

	initialise_colours ();

	always_show =
		eel_gconf_get_boolean (CONF_TABS_TABBED_ALWAYS_SHOW);

	for (w = all_windows; w != NULL; w = g_list_next (w))
	{
		GaleonWindow *window = (GaleonWindow *)(w->data);

		/* check if the tab(s) should be visible */
		n_embeds = g_list_length (window->embed_list);
		if (n_embeds == 1)
		{
			GaleonEmbed *embed;

			e = window->embed_list;
 			embed = (GaleonEmbed *) (e->data);
			popup = window->is_popup;
		}

		gtk_notebook_set_show_tabs (GTK_NOTEBOOK (window->notebook), 
					    (n_embeds > 1) | 
					    (always_show && !popup));

		/* update notebook tabs */
		for (e = window->embed_list; e != NULL; e = g_list_next (e))
		{
			GaleonEmbed *embed = (GaleonEmbed *) (e->data);

			embed_update_tab_title (embed);
			embed_update_tab_close_button (embed);
			embed_update_tab_status (embed);
			embed_update_tab_size (embed);
		}
	}
}
