/*
 *  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.
 */

#include "galeon.h"
#include "embed.h"
#include "misc.h"
#include "bookmarks.h"
#include "history.h"
#include "window.h"
#include "mozilla.h"
#include "downloader.h"
#include "context.h"
#include "eel-gconf-extensions.h"

#include <string.h>
#include <gtkmozembed.h>
#include <gtk/gtkmain.h>
#include <libgnome/gnome-i18n.h>
#include <libgnome/gnome-config.h>
#include <libgnomeui/gnome-app.h>
#include <libgnomeui/gnome-popup-menu.h>
#include <libgnomeui/gnome-stock.h>
#include <libgnomeui/gnome-app-helper.h>
#include <libgnomeui/gtkpixmapmenuitem.h>
#include <libgnomeui/gnome-preferences.h>

#include <libgnomevfs/gnome-vfs.h>

/* defines */
#define CONTEXT_MENU_ITEM(label, stock_id, action) \
 { GNOME_APP_UI_ITEM, label, NULL, NULL, GINT_TO_POINTER(action), NULL, \
 GNOME_APP_PIXMAP_STOCK, stock_id, 0, 0, NULL}
#define CONTEXT_MENU_TOGGLEITEM(label, stock_id, action) \
 { GNOME_APP_UI_TOGGLEITEM, label, NULL, NULL, GINT_TO_POINTER(action), NULL, \
 GNOME_APP_PIXMAP_STOCK, stock_id, 0, 0, NULL}

/* common menus */

/* are these still needed? do we need to make them all like this?*/
static char BACK_STR[]          = N_("Back");
static char FORWARD_STR[]       = N_("Forward");
static char UP_STR[]            = N_("Up");
static char RELOAD_STR[]        = N_("Reload");
static char OPEN_NEW_WIN_STR[]  = N_("Open in new window");
static char OPEN_NEW_TAB_STR[]  = N_("Open in new tab");
static char DOWNLOAD_FILE_STR[] = N_("Download link");
static char COPY_LINK_LOC_STR[] = N_("Copy link location");
static char ADD_BM_STR[]        = N_("Add bookmark");
static char OPEN_IMG_WIN_STR[]  = N_("Open image in new window");
static char OPEN_IMG_TAB_STR[]  = N_("Open image in new tab");
static char SAVE_IMG_STR[]      = N_("Save image");
static char SAVE_IMG_AS_STR[]   = N_("Save image as...");
static char USE_IMG_AS_BG_STR[] = N_("Use image as background");
static char COPY_IMG_LOC_STR[]  = N_("Copy image location");
static char OPEN_FRAME_WIN_STR[]     = N_("Open frame in window");
static char OPEN_FRAME_NEW_WIN_STR[] = N_("Open frame in new window");
static char OPEN_FRAME_NEW_TAB_STR[] = N_("Open frame in new tab");
static char RELOAD_FRAME_STR[]       = N_("Reload frame");
static char COPY_FRAME_LOC_STR[]     = N_("Copy frame location");
static char ADD_BM_FRAME_STR[]       = N_("Add bookmark for frame");
static char VIEW_SOURCE_STR[]        = N_("View source");
static char SAVE_AS_STR[]            = N_("Save As...");
static char FULLSCREEN_STR[]    = N_("Full screen");
static char MENUBAR_VIEW_STR[]  = N_("Show menubar");
static char BGIMG_STR[]         = N_("Save background as...");
static char CUT_STR[]           = N_("Cut");
static char COPY_STR[]          = N_("Copy");
static char PASTE_STR[]         = N_("Paste");

#define NAVIGATION_CONTEXT_MENU \
  CONTEXT_MENU_ITEM(BACK_STR,    GNOME_STOCK_MENU_BACK,    GALEON_CONTEXT_BACK),    \
  CONTEXT_MENU_ITEM(FORWARD_STR, GNOME_STOCK_MENU_FORWARD, GALEON_CONTEXT_FORWARD), \
  CONTEXT_MENU_ITEM(UP_STR,      GNOME_STOCK_MENU_UP,      GALEON_CONTEXT_UP),       \
  CONTEXT_MENU_ITEM(RELOAD_STR,  GNOME_STOCK_MENU_REFRESH, GALEON_CONTEXT_RELOAD),
#define LINK_CONTEXT_MENU \
  CONTEXT_MENU_ITEM(OPEN_NEW_WIN_STR,  GNOME_STOCK_MENU_NEW,   GALEON_CONTEXT_OPENWINDOW), \
  CONTEXT_MENU_ITEM(OPEN_NEW_TAB_STR,  GNOME_STOCK_MENU_NEW,   GALEON_CONTEXT_OPENTAB),    \
  CONTEXT_MENU_ITEM(DOWNLOAD_FILE_STR, GNOME_STOCK_MENU_SAVE,  GALEON_CONTEXT_DOWNLOAD), \
  CONTEXT_MENU_ITEM(COPY_LINK_LOC_STR, GNOME_STOCK_MENU_COPY,  GALEON_CONTEXT_COPYLOC),    \
  CONTEXT_MENU_ITEM(ADD_BM_STR,        GNOME_STOCK_MENU_BLANK, GALEON_CONTEXT_ADDTEMPBMLINK),
/* 
 * The first item is "Open Image (%s)", the last is "Block images from %s"
 * These are defined as NULL here and added in fill_in_image_context_menu
 */
#define IMAGE_CONTEXT_MENU \
  CONTEXT_MENU_ITEM(NULL,              GNOME_STOCK_MENU_OPEN,    GALEON_CONTEXT_OPENIMAGE),       \
  CONTEXT_MENU_ITEM(OPEN_IMG_WIN_STR,  GNOME_STOCK_MENU_NEW,     GALEON_CONTEXT_OPENIMAGEWINDOW), \
  CONTEXT_MENU_ITEM(OPEN_IMG_TAB_STR,  GNOME_STOCK_MENU_NEW,     GALEON_CONTEXT_OPENIMAGETAB),    \
  CONTEXT_MENU_ITEM(SAVE_IMG_STR,      GNOME_STOCK_MENU_SAVE,    GALEON_CONTEXT_SAVEIMAGE),       \
  CONTEXT_MENU_ITEM(SAVE_IMG_AS_STR,   GNOME_STOCK_MENU_SAVE_AS, GALEON_CONTEXT_SAVEIMAGEAS),     \
  CONTEXT_MENU_ITEM(USE_IMG_AS_BG_STR, GNOME_STOCK_MENU_BLANK,   GALEON_CONTEXT_USEIMAGEASBG),    \
  CONTEXT_MENU_ITEM(COPY_IMG_LOC_STR,  GNOME_STOCK_MENU_COPY,    GALEON_CONTEXT_COPYIMAGELOC),    \
  CONTEXT_MENU_ITEM(NULL,              GNOME_STOCK_MENU_BLANK,   GALEON_CONTEXT_BLOCKIMAGESOURCE),
#define FRAME_CONTEXT_MENU \
  CONTEXT_MENU_ITEM(OPEN_FRAME_WIN_STR,     GNOME_STOCK_MENU_OPEN,    GALEON_CONTEXT_OPENFRAME),       \
  CONTEXT_MENU_ITEM(OPEN_FRAME_NEW_WIN_STR, GNOME_STOCK_MENU_OPEN,    GALEON_CONTEXT_OPENFRAMEWINDOW), \
  CONTEXT_MENU_ITEM(OPEN_FRAME_NEW_TAB_STR, GNOME_STOCK_MENU_OPEN,    GALEON_CONTEXT_OPENFRAMETAB),    \
  CONTEXT_MENU_ITEM(RELOAD_FRAME_STR,       GNOME_STOCK_MENU_REFRESH, GALEON_CONTEXT_RELOADFRAME),     \
  CONTEXT_MENU_ITEM(COPY_FRAME_LOC_STR,     GNOME_STOCK_MENU_COPY,    GALEON_CONTEXT_COPYFRAMELOC),    \
  CONTEXT_MENU_ITEM(ADD_BM_FRAME_STR,       GNOME_STOCK_MENU_BLANK,   GALEON_CONTEXT_ADDTEMPBMFRAME),
#define SHORT_CONTEXT_MENU \
  CONTEXT_MENU_ITEM(COPY_LINK_LOC_STR, GNOME_STOCK_MENU_COPY,  GALEON_CONTEXT_COPYDOCLOC),    \
  CONTEXT_MENU_ITEM(SAVE_AS_STR,               GNOME_STOCK_MENU_SAVE_AS, GALEON_CONTEXT_SAVEAS),     \
  CONTEXT_MENU_ITEM(BGIMG_STR,		       GNOME_STOCK_MENU_SAVE_AS, GALEON_CONTEXT_BGIMG),	\
  CONTEXT_MENU_ITEM(VIEW_SOURCE_STR,           GNOME_STOCK_MENU_BLANK,   GALEON_CONTEXT_VIEWSOURCE),     \
  CONTEXT_MENU_TOGGLEITEM(FULLSCREEN_STR,      GNOME_STOCK_MENU_BLANK,   GALEON_CONTEXT_FULLSCREEN), \
  CONTEXT_MENU_ITEM(MENUBAR_VIEW_STR,          GNOME_STOCK_MENU_BLANK,   GALEON_CONTEXT_MENUBAR), \
  CONTEXT_MENU_ITEM(ADD_BM_STR,                GNOME_STOCK_MENU_BLANK,   GALEON_CONTEXT_ADDTEMPBM),
#define CLIPBOARD_CONTEXT_MENU \
  CONTEXT_MENU_ITEM(CUT_STR,   GNOME_STOCK_MENU_CUT,    GALEON_CONTEXT_CUT),    \
  CONTEXT_MENU_ITEM(COPY_STR,  GNOME_STOCK_MENU_COPY,   GALEON_CONTEXT_COPY),    \
  CONTEXT_MENU_ITEM(PASTE_STR, GNOME_STOCK_MENU_PASTE,  GALEON_CONTEXT_PASTE),  
  
/* local data structures */
typedef enum
{
	GALEON_CONTEXT_NONE,
	GALEON_CONTEXT_BACK,
	GALEON_CONTEXT_FORWARD,
	GALEON_CONTEXT_UP,
	GALEON_CONTEXT_RELOAD,
	GALEON_CONTEXT_SAVEAS,
	GALEON_CONTEXT_FULLSCREEN,
	GALEON_CONTEXT_MENUBAR,
	GALEON_CONTEXT_ADDTEMPBM,
	GALEON_CONTEXT_OPENWINDOW,
	GALEON_CONTEXT_OPENTAB,
	GALEON_CONTEXT_DOWNLOAD,
	GALEON_CONTEXT_COPYLOC,
	GALEON_CONTEXT_COPYDOCLOC,
	GALEON_CONTEXT_ADDTEMPBMLINK,
	GALEON_CONTEXT_OPENIMAGE,
	GALEON_CONTEXT_OPENIMAGEWINDOW,
	GALEON_CONTEXT_OPENIMAGETAB,
	GALEON_CONTEXT_SAVEIMAGE,
	GALEON_CONTEXT_SAVEIMAGEAS,
	GALEON_CONTEXT_USEIMAGEASBG,
	GALEON_CONTEXT_COPYIMAGELOC,
	GALEON_CONTEXT_BLOCKIMAGESOURCE,
	GALEON_CONTEXT_OPENFRAME,
	GALEON_CONTEXT_OPENFRAMEWINDOW,
	GALEON_CONTEXT_OPENFRAMETAB,
	GALEON_CONTEXT_RELOADFRAME,
	GALEON_CONTEXT_COPYFRAMELOC,
	GALEON_CONTEXT_ADDTEMPBMFRAME,
	GALEON_CONTEXT_VIEWSOURCE,
	GALEON_CONTEXT_BGIMG,
	GALEON_CONTEXT_CUT,
	GALEON_CONTEXT_COPY,
	GALEON_CONTEXT_PASTE
} GaleonContextAction;

typedef enum
{
	GALEON_CONTEXT_LINK = CONTEXT_LINK | CONTEXT_DOCUMENT,
	GALEON_CONTEXT_IMAGELINK = CONTEXT_LINK | CONTEXT_IMAGE | CONTEXT_DOCUMENT,
	GALEON_CONTEXT_DOC = CONTEXT_DOCUMENT,
	GALEON_CONTEXT_IMAGE = CONTEXT_IMAGE | CONTEXT_DOCUMENT,
	GALEON_CONTEXT_INPUT = CONTEXT_DOCUMENT | CONTEXT_INPUT
} GaleonContextEvent;

/* local functions */
static GnomeUIInfo *context_make_menu 	     (WrapperContextInfo *info);
static guint context_show_context_menu 	     (GaleonEmbed *embed, 
					      GnomeUIInfo *menu,
					      int button,
					      guint timestamp,
					      WrapperContextInfo *info);
static void context_do_action 		     (GaleonContextAction action, 
					      WrapperContextInfo *info,
					      GaleonEmbed *embed);
static void context_set_navigation_buttons   (GaleonEmbed *embed, 
					      GnomeUIInfo *uiinfo,
					      GtkWidget *popup);
static void context_set_full_screen_check    (GaleonWindow *window,
					      GnomeUIInfo *menu,
					      GtkWidget *popup);
static void context_set_menu_bar_check       (GaleonWindow *window,
					      GnomeUIInfo *menu,
					      GtkWidget *popup);
static void context_set_background_image     (GaleonWindow *window,
					      GnomeUIInfo *menu,
					      WrapperContextInfo *info);
static void context_set_clipboard_buttons (GaleonEmbed *embed, 
					   GnomeUIInfo *uiinfo,
					   GtkWidget *popup);
static void context_menu_add_bookmarks (GtkMenu *menu, GaleonEmbed *embed);
static BookmarkItem *context_menu_create_fake_bookmarks_root (void);
static void context_menu_create_fake_bookmarks_root_recursively 
						(BookmarkItem *b, GList **l);
static void fill_in_image_context_menu (gchar *imagename, 
	gint pos, GnomeUIInfo *uiinfo);

/* local variables */
static gboolean found_bookmarks = FALSE;

extern gboolean fullscreen_active;

/**
 * context_set_full_screen_check: searches for a check button and sets it
 **/
static void context_set_full_screen_check (GaleonWindow *window,
					   GnomeUIInfo *menu,
					   GtkWidget *popup)
{
	gint i;

	return_if_not_window (window);

	for (i = 0; menu[i].type != GNOME_APP_UI_ENDOFINFO; i++)
	{
		if (GPOINTER_TO_INT (menu[i].user_data) == 
		    GALEON_CONTEXT_FULLSCREEN)
		{
			GtkCheckMenuItem *menu_view_fullscreen = 
				GTK_CHECK_MENU_ITEM (menu[i].widget);
			g_return_if_fail (menu_view_fullscreen != NULL); 
			gtk_check_menu_item_set_active (menu_view_fullscreen,
							fullscreen_active);
		}
	}
}

/**
 * context_set_menu_bar_check: searches for a check button and sets it
 **/
static void context_set_menu_bar_check (GaleonWindow *window,
					GnomeUIInfo *menu,
					GtkWidget *popup)
{
	gint i;

	return_if_not_window (window);

	for (i = 0; menu[i].type != GNOME_APP_UI_ENDOFINFO; i++)
	{
		if (GPOINTER_TO_INT (menu[i].user_data) == 
		    GALEON_CONTEXT_MENUBAR)
		{
			GtkMenuItem *menu_view_menubar = 
				GTK_MENU_ITEM (menu[i].widget);
			g_return_if_fail (menu_view_menubar != NULL); 
			if (GTK_CHECK_MENU_ITEM (window->view_menubar)->active)
			{
				gtk_widget_hide
					(GTK_WIDGET (menu_view_menubar));
			}
		}
	}
}

/**
 * context_set_menu_bar_check: searches for a check button and sets it
 **/
static void context_set_background_image (GaleonWindow *window,
					  GnomeUIInfo *menu,
					  WrapperContextInfo *info)
{
	gint i;

	return_if_not_window (window);

	for (i = 0; menu[i].type != GNOME_APP_UI_ENDOFINFO; i++)
	{
		if (GPOINTER_TO_INT (menu[i].user_data) == 
		    GALEON_CONTEXT_BGIMG)
		{
			GtkMenuItem *m = GTK_MENU_ITEM (menu[i].widget);
			g_return_if_fail (m != NULL); 
			if (info->bgimg == NULL)
			{
				gtk_widget_hide (GTK_WIDGET (m));
			}
		}
	}
}

/**
 * context_set_navigation_buttons: sets up back/forward/up buttons
 */
static void context_set_navigation_buttons (GaleonEmbed *embed, 
					    GnomeUIInfo *uiinfo,
					    GtkWidget *popup)
{
	gboolean can_go_back, can_go_forward, can_go_up;
	gboolean show_history_popup;
	GtkMenu *menu_back, *menu_forward, *menu_up;
	gint context_action, i;
	gint go_back_pos = 0, go_forward_pos = 1, go_up_pos = 2;
	
	show_history_popup = 
	      eel_gconf_get_boolean (CONF_MOUSE_HISTORY_POPUP);
	can_go_back = gtk_moz_embed_can_go_back 
		(GTK_MOZ_EMBED(embed->mozEmbed));
	can_go_forward = gtk_moz_embed_can_go_forward 
		(GTK_MOZ_EMBED(embed->mozEmbed));
	can_go_up = embed_can_go_up (embed);
	
	for (i = 0; uiinfo[i].type != GNOME_APP_UI_ENDOFINFO; i++)
	{
		context_action = GPOINTER_TO_INT (uiinfo[i].user_data);

		if (context_action == GALEON_CONTEXT_BACK)
		{
			go_back_pos    = i;
			go_forward_pos = i + 1;
			go_up_pos      = i + 2;

			gtk_widget_set_sensitive(uiinfo[go_back_pos].widget, 
						 can_go_back);
			gtk_widget_set_sensitive(uiinfo[go_forward_pos].widget, 
						 can_go_forward);
			gtk_widget_set_sensitive (uiinfo[go_up_pos].widget, 
						  can_go_up);

			break;
		}
	}

	if (show_history_popup)
	{
		if (can_go_back && 
		    (menu_back = embed_create_back_menu(embed)) != NULL)
		{
			gtk_signal_connect(
				GTK_OBJECT(menu_back),
				"selection-done",
				(GtkSignalFunc)popup_selection_done_cb,
				popup);
			gnome_popup_menu_attach(
				GTK_WIDGET(menu_back),
				uiinfo[go_back_pos].widget,
				NULL);
		}      
		if (can_go_forward && 
		    (menu_forward = embed_create_forward_menu(embed)) != NULL)
		{
			gtk_signal_connect(
				GTK_OBJECT(menu_forward),
				"selection-done",
				(GtkSignalFunc)popup_selection_done_cb,
				popup);
			gnome_popup_menu_attach(
				GTK_WIDGET(menu_forward),
				uiinfo[go_forward_pos].widget,
				NULL);
		}
		if (can_go_up &&
		    (menu_up = embed_create_up_menu (embed)) != NULL)
		{
			gtk_signal_connect(
				GTK_OBJECT(menu_up),
				"selection-done",
				(GtkSignalFunc)popup_selection_done_cb,
				popup);
			gnome_popup_menu_attach (GTK_WIDGET(menu_up),
					 uiinfo[go_up_pos].widget, NULL);
		}
	}
}

/**
 * context_set_clipboard_buttons: sets up cut/copy/paste buttons
 */
static void context_set_clipboard_buttons (GaleonEmbed *embed, 
					   GnomeUIInfo *uiinfo,
					   GtkWidget *popup)
{
	gboolean can_copy, can_cut, can_paste;
	gint context_action, i;
	gint copy_pos = 1, cut_pos = 0, paste_pos = 2;
	
	can_cut = mozilla_can_cut_selection (embed);
	can_copy = mozilla_can_copy_selection (embed);
	can_paste = mozilla_can_paste (embed);
	
	for (i = 0; uiinfo[i].type != GNOME_APP_UI_ENDOFINFO; i++)
	{
		context_action = GPOINTER_TO_INT (uiinfo[i].user_data);

		if (context_action == GALEON_CONTEXT_CUT)
		{
			cut_pos = i;
			copy_pos = i + 1;
			paste_pos = i + 2;

			gtk_widget_set_sensitive(uiinfo[cut_pos].widget, 
						 can_cut);
			gtk_widget_set_sensitive(uiinfo[copy_pos].widget, 
						 can_copy);
			gtk_widget_set_sensitive (uiinfo[paste_pos].widget, 
						  can_paste);

			break;
		}
	}
}

/**
 * context_make_menu: helper func to create the correct menu
 **/
static GnomeUIInfo *context_make_menu (WrapperContextInfo *info)
{
	switch (info->context) /* there has to be a better way too do this, */
	{                      /* nonetheless it evaded me */
	case GALEON_CONTEXT_LINK:
	{
		GnomeUIInfo link_uiinfo[] =
		{
			LINK_CONTEXT_MENU
			GNOMEUIINFO_SEPARATOR,
			NAVIGATION_CONTEXT_MENU
			GNOMEUIINFO_END
		};
		return g_memdup (&link_uiinfo, sizeof(link_uiinfo));
	}
	case GALEON_CONTEXT_IMAGELINK:
	{
		GnomeUIInfo imagelink_uiinfo[] =
		{
			LINK_CONTEXT_MENU
			GNOMEUIINFO_SEPARATOR,
			IMAGE_CONTEXT_MENU
			GNOMEUIINFO_SEPARATOR,
			NAVIGATION_CONTEXT_MENU
			GNOMEUIINFO_END
		};
		fill_in_image_context_menu (info->img, 6, imagelink_uiinfo);
                return g_memdup (&imagelink_uiinfo, sizeof(imagelink_uiinfo));
	}
	case GALEON_CONTEXT_DOC:
	{
		if (info->framed_page)
		{
			GnomeUIInfo framed_uiinfo[] =
			{
				NAVIGATION_CONTEXT_MENU
				GNOMEUIINFO_SEPARATOR,
				SHORT_CONTEXT_MENU
				GNOMEUIINFO_SEPARATOR,
				FRAME_CONTEXT_MENU
				GNOMEUIINFO_END
			};
			
			return g_memdup (&framed_uiinfo, sizeof(framed_uiinfo));
		}
		else
		{
			GnomeUIInfo doc_uiinfo[] =
			{
				NAVIGATION_CONTEXT_MENU
				GNOMEUIINFO_SEPARATOR,
				SHORT_CONTEXT_MENU
				GNOMEUIINFO_END
			};
			return g_memdup (&doc_uiinfo, sizeof(doc_uiinfo));
		}
		break;
	}
	case GALEON_CONTEXT_IMAGE:
	{
		GnomeUIInfo image_uiinfo[] =
		{
			NAVIGATION_CONTEXT_MENU
			GNOMEUIINFO_SEPARATOR,
			IMAGE_CONTEXT_MENU
			GNOMEUIINFO_END
		};
		fill_in_image_context_menu (info->img, 5, image_uiinfo);
                return g_memdup (&image_uiinfo, sizeof(image_uiinfo));
	}
	case GALEON_CONTEXT_INPUT:
	{
		GnomeUIInfo input_uiinfo[] =
		{
			CLIPBOARD_CONTEXT_MENU
			GNOMEUIINFO_SEPARATOR,
			NAVIGATION_CONTEXT_MENU
			GNOMEUIINFO_END
		};
		return g_memdup (&input_uiinfo, sizeof(input_uiinfo));
	}
	default:
		g_warning ("No menu data for that context\n");
		return NULL;
	}
}

/**
 * context_show_menu: show appropriate context menu based on the target type
 **/
static guint context_show_context_menu (GaleonEmbed *embed, 
					GnomeUIInfo *menu,
					int button,
					guint timestamp,
					WrapperContextInfo *info)
{
	guint ret;
	GtkWidget *popup;
	GdkEventButton *event = NULL;
	GList *l;
	/* Create a fake GdkEventButton struct for gnome_popup_menu_new so that
	 * we can get standard gtk popup menu behavior.
	 * button and time are the only fields it needs. */
	if (button>0)
	{
		event = g_new0 (GdkEventButton, 1);
		event->button = button;
		event->time = timestamp;
	}
	popup = gnome_popup_menu_new (menu);
	context_set_navigation_buttons (embed, menu, popup);
	context_set_clipboard_buttons (embed, menu, popup);
	context_set_full_screen_check (embed->parent_window, menu, popup);
	context_set_menu_bar_check (embed->parent_window, menu, popup);
	context_set_background_image (embed->parent_window, menu, info);
	context_menu_add_bookmarks (GTK_MENU (popup), embed);
	for (l = GTK_MENU (popup)->menu_shell.children; l; l = g_list_next (l))
	{
		gtk_widget_lock_accelerators (GTK_WIDGET (l->data));
	}
	ret = gnome_popup_menu_do_popup_modal (popup, NULL, NULL,
					       event , NULL);
	/* Wait for the menu to be destroyed if a menu item is selected */
	if (ret != -1) 
		while (gtk_events_pending()) 
			gtk_main_iteration();

	gtk_widget_unref (popup);
	g_free (event);
	return ret;
}

/**
 * context_do_action: performs the acual action
 **/
static void context_do_action (GaleonContextAction action, 
			       WrapperContextInfo *info,
			       GaleonEmbed *embed)
{
	gchar *url;

	gboolean tabbed_mode = eel_gconf_get_boolean (CONF_TABS_TABBED);

	switch (action)
	{
	case GALEON_CONTEXT_NONE:
		break;
	case GALEON_CONTEXT_BACK:
		gtk_moz_embed_go_back (GTK_MOZ_EMBED(embed->mozEmbed));
		break;
	case GALEON_CONTEXT_FORWARD:
		gtk_moz_embed_go_forward (GTK_MOZ_EMBED(embed->mozEmbed));
		break;
	case GALEON_CONTEXT_UP:
		embed_go_up (embed, 0, 0);
		break;
	case GALEON_CONTEXT_RELOAD:
		embed_reload (embed, GTK_MOZ_EMBED_FLAG_RELOADNORMAL);
		break;
	case GALEON_CONTEXT_SAVEAS:
		embed_save_document (embed, FALSE);
		break;
	case GALEON_CONTEXT_FULLSCREEN:
		window_toggle_fullscreen_mode (embed->parent_window);
		break;
	case GALEON_CONTEXT_MENUBAR:
		gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM 
			(embed->parent_window->view_menubar), TRUE);
		break;
	case GALEON_CONTEXT_ADDTEMPBM:
		if (default_bookmarks_root) 
			bookmarks_file_bookmark_cb (embed->parent_window->WMain,
						    default_bookmarks_root);
		break;
	case GALEON_CONTEXT_BGIMG:
		embed_save_image (embed, info->bgimg, TRUE);
		break;
	case GALEON_CONTEXT_OPENWINDOW:
		embed_create_from_url (embed, info->link, FALSE, TRUE);
		break;
	case GALEON_CONTEXT_OPENTAB:
		embed_create_from_url (embed, info->link, FALSE, FALSE);
		break;
	case GALEON_CONTEXT_DOWNLOAD:
		downloader_save_link (embed, info->link);
		break;
	case GALEON_CONTEXT_COPYLOC:
		copy_to_clipboard (info->link, embed);
		break;
	case GALEON_CONTEXT_COPYDOCLOC:
		copy_to_clipboard (embed->site_location, embed);
		break;
	case GALEON_CONTEXT_ADDTEMPBMLINK:
		add_temp_link_bookmark (info->linktext, info->link, NULL);
		break;
	case GALEON_CONTEXT_OPENIMAGE:
		embed_load_url(embed, info->img);
		break;
	case GALEON_CONTEXT_OPENIMAGEWINDOW:
		embed_create_from_url (embed, info->img, FALSE, TRUE);
		break;
	case GALEON_CONTEXT_OPENIMAGETAB:
		embed_create_from_url (embed, info->img, FALSE, FALSE);
		break;
	case GALEON_CONTEXT_SAVEIMAGE:
		embed_save_image (embed, info->img, FALSE);
		break;
	case GALEON_CONTEXT_SAVEIMAGEAS:
		embed_save_image (embed, info->img, TRUE);
		break;
	case GALEON_CONTEXT_USEIMAGEASBG:
		embed_set_image_as_background (embed, info->img);
		break;
	case GALEON_CONTEXT_COPYIMAGELOC:
		copy_to_clipboard (g_strdup (info->img), embed);
		break;
	case GALEON_CONTEXT_BLOCKIMAGESOURCE:
		embed_toggle_image_blocking (info->img);
		break;
	case GALEON_CONTEXT_OPENFRAME:
		embed_open_frame (embed, TRUE, FALSE);
		break;
	case GALEON_CONTEXT_OPENFRAMEWINDOW:
		embed_open_frame (embed, FALSE, TRUE);
		break;
	case GALEON_CONTEXT_OPENFRAMETAB:
		embed_open_frame (embed, FALSE, FALSE);
		break;
	case GALEON_CONTEXT_RELOADFRAME:
		mozilla_reload (embed);
		break;
	case GALEON_CONTEXT_COPYFRAMELOC:
		url = mozilla_get_document_url (embed);
		if (url)
		{
			copy_to_clipboard (url, embed);
			g_free (url);
		}
		break;
	case GALEON_CONTEXT_ADDTEMPBMFRAME:
		url = mozilla_get_document_url (embed);
		if (url)
		{
			add_bookmark_default
				(BM_SITE, (embed->site_title_utf8 
					   ? embed->site_title_utf8
					   : embed->site_title), 
				 url, NULL);
			g_free (url);
		}
		break;
	case GALEON_CONTEXT_VIEWSOURCE:
		embed_view_source (embed, FALSE, !tabbed_mode);
		break;
	case GALEON_CONTEXT_CUT:
		mozilla_cut_selection (embed);
		break;
	case GALEON_CONTEXT_COPY:
		mozilla_copy_selection (embed);
		break;
	case GALEON_CONTEXT_PASTE:
		mozilla_paste (embed);
		break;
	default:
		/* nothing happened, most likely the user did not end up
		   selecting an item from the popup */
		break;
	}
}

/**
 * context_show_menu: show appropriate context menu based on the target type
 **/
void context_show_menu (GaleonEmbed *embed, WrapperContextInfo *info,
			int button, guint timestamp)
{
	GnomeUIInfo *menu;

	return_if_not_embed (embed);
	menu = context_make_menu (info);
	
	if (menu != NULL)
	{
		guint result = context_show_context_menu (embed, menu, button,
							  timestamp, info);
		if (result != -1)
		{
			GaleonContextAction action = 
				GPOINTER_TO_INT(menu[result].user_data);
			context_do_action (action, info, embed);
		}
		g_free (menu);
	}
}

/**
 * context_show_bookmark_menu: show a bookmarks popup menu 
 **/
void context_show_bookmark_menu (GaleonEmbed *embed)
{
	GtkWidget *menu;
	GtkTooltips *tips;
	GaleonWindow *window;

	return_if_not_embed (embed);
	window = embed->parent_window;
	return_if_not_window (window);
	
	menu = gtk_menu_new ();
	tips = gtk_tooltips_new ();
	bookmarks_menu_create_recursively (bookmarks_root, GTK_MENU (menu),
					   NULL, tips, TRUE, TRUE, TRUE);
	
	/* warning: ugly code */
	gtk_object_set_data (GTK_OBJECT (menu), "GaleonWindow", window); 
	gnome_popup_menu_do_popup_modal (menu, NULL, NULL,
					 NULL , NULL);
	gtk_widget_unref (menu);
	gtk_object_destroy (GTK_OBJECT(tips));
}

/**
 * context_show_appearance_menu: creates a submenu with
 * different toolbar styles
 */
void
context_show_appearance_menu (GaleonWindow *window, GtkMenu *menu, 
			      BookmarkItem *bi, gboolean is_button, 
			      gboolean in_submenu)
{
	GtkMenu *appearance_menu;
	GtkWidget *appearance_menu_item;
	GSList *radiogroup = NULL;
	ToolbarStyle style;

	if (in_submenu)
	{
		appearance_menu = GTK_MENU (gtk_menu_new ());
		appearance_menu_item = gtk_menu_item_new_with_label ("");
		label_set_accel_text (_("_Appearance"),
				      GTK_BIN (appearance_menu_item)->child, 
				      GTK_WIDGET (menu),
				      appearance_menu_item);
		gtk_menu_item_set_submenu (GTK_MENU_ITEM (appearance_menu_item),
					   GTK_WIDGET (appearance_menu));
		gtk_menu_append (menu, GTK_WIDGET (appearance_menu_item));
		gtk_widget_show (GTK_WIDGET (appearance_menu_item));
	}
	else
	{
		appearance_menu = menu;
	}

	if (bi)
	{
		/* we're on a bookmark toolbar */
		
		if (is_button)
			bi = bi->parent;

		style = bi->toolbar_style;

		context_menu_add_radio_item 
			(appearance_menu, _("Text _beside icons"),
			 context_bm_toolbar_appearance_menu_cb, bi,
			 (style == TOOLBAR_STYLE_HORIZONTAL), &radiogroup);
		context_menu_add_radio_item 
			(appearance_menu, _("Text _under icons"),
			 context_bm_toolbar_appearance_menu_cb, bi,
			 (style == TOOLBAR_STYLE_VERTICAL), &radiogroup);
		context_menu_add_radio_item 
			(appearance_menu, _("_Text only"),
			 context_bm_toolbar_appearance_menu_cb, bi,
			 (style == TOOLBAR_STYLE_TEXT_ONLY), &radiogroup);
	}
	else
	{
		/* we're on the main toolbar */

		style = eel_gconf_get_integer (CONF_TOOLBAR_STYLE);
		context_menu_add_radio_item 
			(appearance_menu, _("Text _beside icons"),
			 context_main_toolbar_appearance_menu_cb, NULL,
			 (style == TOOLBAR_STYLE_HORIZONTAL), &radiogroup);
		context_menu_add_radio_item 
			(appearance_menu, _("Text _under icons"),
			 context_main_toolbar_appearance_menu_cb, NULL,
			 (style == TOOLBAR_STYLE_VERTICAL), &radiogroup);
		context_menu_add_radio_item 
			(appearance_menu, _("_Text only"),
			 context_main_toolbar_appearance_menu_cb, NULL,
			 (style == TOOLBAR_STYLE_TEXT_ONLY), &radiogroup);
		context_menu_add_radio_item 
			(appearance_menu, _("_Icons only"),
			 context_main_toolbar_appearance_menu_cb, NULL,
			 (style == TOOLBAR_STYLE_ICONS_ONLY), &radiogroup);

		context_menu_add_seperator (appearance_menu);

		context_menu_add_item (appearance_menu, _("_Edit toolbar..."),
				       context_main_toolbar_edit_toolbar_cb,
				       window, GNOME_STOCK_MENU_PROP, TRUE);
	}
}

/**
 * context_menu_add_bookmarks: add the bookmarks that have the 
 * create_context_menu flag to a menu
 */
static void
context_menu_add_bookmarks (GtkMenu *menu, GaleonEmbed *embed)
{
	GtkTooltips *tips = gtk_tooltips_new ();
	GtkWidget *new_item;
	GaleonWindow *window;
	BookmarkItem *fake_bookmarks_root = 
		context_menu_create_fake_bookmarks_root ();

	return_if_not_embed (embed);
	window = embed->parent_window;
	return_if_not_window (window);

	new_item = gtk_menu_item_new ();
	gtk_menu_append (menu, new_item);

	if (found_bookmarks)
	{
		context_menu_add_seperator (menu);
		found_bookmarks = FALSE;
	}
	
	bookmarks_menu_create_recursively (fake_bookmarks_root, 
					   menu, NULL, tips, FALSE,
					   TRUE, TRUE);
	
	bookmarks_free_bookmark (fake_bookmarks_root);

	/* warning: ugly code */
	gtk_object_set_data (GTK_OBJECT (menu), "GaleonWindow", window); 
	gtk_signal_connect_object (GTK_OBJECT (menu), "destroy", 
				   gtk_object_unref, GTK_OBJECT (tips));
}

/**
 * fill_in_image_context_menu: fill in the image part
 * of the context menu with the image name
 */
static void
fill_in_image_context_menu (gchar *imagename, gint pos,
			GnomeUIInfo *uiinfo)
{
	gchar *name, *s;
	const gchar *host = NULL;
	gint length;
	GnomeVFSURI *vfs_uri = gnome_vfs_uri_new (imagename);
	GList *permissions, *l;
	gboolean blocked = FALSE;

	g_assert (imagename != NULL);
	
	s = g_strdup (g_basename (imagename));
	length = strlen (s);
	
	/* shorten the name if needed*/
	if (length > 40)
	{
		gchar *tmp = g_strdup_printf ("%.29s...%s", s, s + length - 8);
		g_free (s);
		s = tmp;
	}
	
	name = escape_uline_accel (s);
	g_free(uiinfo[pos].label);
	uiinfo[pos].label = 
		g_strdup_printf (_("Open image (%s)"), name);

	g_free (s);
	g_free (name);

	if (vfs_uri)
		host = gnome_vfs_uri_get_host_name (vfs_uri);
	permissions = mozilla_get_permissions (IMAGEPERMISSION);

	for (l = permissions; l && blocked == FALSE; l = g_list_next (l))
	{
		CookieBase *b = (CookieBase *) l->data;
		if (host && strcmp (host, b->domain) == 0)
			blocked = TRUE;
		g_free (b->type);
		g_free (b->domain);
		g_free (b);
	}

	g_list_free (permissions);
	
	g_free (uiinfo[pos+7].label);

	if (blocked == FALSE)
	{
		if (host)
		{
			uiinfo[pos+7].label = 
				g_strdup_printf (_("Block images from %s"),
						 host);
		}
		else
		{
			uiinfo[pos+7].label = 
				g_strdup (_("Block image source"));
		}
	}
	else
	{
		if (host)
		{
			uiinfo[pos+7].label = 
				g_strdup_printf (_("Allow images from %s"),
						 host);
		}
		else
		{
			uiinfo[pos+7].label = 
				g_strdup (_("Allow image source"));
		}	
	}

	if (vfs_uri) gnome_vfs_uri_unref(vfs_uri);
}

/**
 * Create a fake bookmark folder that haves all the bookmarks that need to be
 * addeed to context menus
 */
static BookmarkItem *
context_menu_create_fake_bookmarks_root (void)
{
	BookmarkItem *r = bookmarks_new_bookmark 
		(BM_FOLDER, TRUE, "fake bookmark", NULL, NULL, NULL, NULL);
	context_menu_create_fake_bookmarks_root_recursively 
		(bookmarks_root, &r->list);
	return r;
}

static void
context_menu_create_fake_bookmarks_root_recursively (BookmarkItem *b, 
						     GList **l)
{
	GList *li;
	if (b->create_context_menu)
	{
		found_bookmarks = TRUE;
		*l = g_list_append (*l, b);
	}
	if (!b->alias_of)
		for (li = b->list; li; li = li->next)
			context_menu_create_fake_bookmarks_root_recursively
				(li->data, l);
}


void
context_menu_add_seperator (GtkMenu *extra_menu)
{
	GtkWidget *separator = gtk_menu_item_new();
	gtk_menu_append (extra_menu, separator);
	gtk_widget_show (separator);
}

void
context_menu_add_item (GtkMenu *extra_menu, const gchar *text,
		       GtkSignalFunc cb_func, void *cb_data, 
		       const char * icon, gboolean sensitive)
{
	GtkWidget *item;
	GtkWidget *hb = gtk_hbox_new (FALSE, 0);
	GtkWidget *label = gtk_label_new ("");

	if (icon)
	{
		item = gtk_pixmap_menu_item_new();
		gtk_pixmap_menu_item_set_pixmap (GTK_PIXMAP_MENU_ITEM (item),
			gnome_stock_pixmap_widget (GTK_WIDGET (extra_menu),
				icon));
	}
	else
	{
		item = gtk_menu_item_new();	
	}

	label_set_accel_text (text, label,
			      GTK_WIDGET (extra_menu), item);
	gtk_box_pack_start (GTK_BOX (hb), label, FALSE, FALSE, 2);
	gtk_container_add (GTK_CONTAINER(item), hb);

	gtk_widget_set_sensitive (item, sensitive);

	gtk_signal_connect (GTK_OBJECT (item), "activate",
			GTK_SIGNAL_FUNC (cb_func), cb_data);
	gtk_menu_append (extra_menu, item);
	gtk_widget_lock_accelerators (item);
	gtk_widget_show_all (item);
}

void
context_menu_add_check_item (GtkMenu *extra_menu, const gchar *text,
				GtkSignalFunc cb_func, void *cb_data,
				gboolean checked)
{
	GtkWidget *item = gtk_check_menu_item_new_with_label ("");
	label_set_accel_text (text, GTK_BIN (item)->child,
			      GTK_WIDGET (extra_menu), item);
	gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), checked);
	gtk_signal_connect (GTK_OBJECT (item), "activate",
			GTK_SIGNAL_FUNC (cb_func), cb_data);
	gtk_menu_append (extra_menu, item);
	gtk_widget_lock_accelerators (item);
	gtk_widget_show (item);
}

void
context_menu_add_radio_item (GtkMenu *extra_menu, const gchar *text,
				GtkSignalFunc cb_func, void *cb_data,
				gboolean checked, GSList **group)
{
	GtkWidget *item = gtk_radio_menu_item_new_with_label (*group, "");
	*group = gtk_radio_menu_item_group (GTK_RADIO_MENU_ITEM (item));
	label_set_accel_text (text, GTK_BIN (item)->child,
			      GTK_WIDGET (extra_menu), item);
	GTK_CHECK_MENU_ITEM (item)->active = checked;
	gtk_signal_connect (GTK_OBJECT (item), "activate",
			    GTK_SIGNAL_FUNC (cb_func), cb_data);
	gtk_menu_append (extra_menu, item);
	gtk_widget_lock_accelerators (item);
	gtk_widget_show (item);
}
