/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */

/*
 *  Copyright (C) 2003 Takuro Ashie
 *
 *  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 /* HAVE_CONFIG_H */

#include "kz-actions-popup.h"

#include <string.h>
#include <glib/gi18n.h>
#ifdef HAVE_UNISTD_H
#  include <unistd.h>
#endif
#include "kz-entry-action.h"
#include "gtk-utils.h"
#include "glib-utils.h"
#include "kazehakase.h"
#include "kz-window.h"
#include "kz-tab-label.h"
#include "kz-actions-download.h"
#include "kz-web.h"
#include "kz-favicon.h"
#include "kz-xml.h"
#include "kz-actions-dynamic.h"
#include "kz-icons.h"
#include "kz-notebook.h"

#define KZ_ACTIONS_POPUP_LANGUAGE_KEY "KzActionsPopup::Language"
#define KZ_ACTIONS_POPUP_TAB_KEY "KzActionsPopup::Tab"

typedef enum {
	LOCATION_LINK,
	LOCATION_IMAGE,
	LOCATION_FRAME		
} LocationType;

typedef enum {
	CURRENT_TAB,
	NEW_TAB,
	NEW_WINDOW
} WindowType;


typedef struct
{
	KzWeb *kzweb;
	gchar *filename;  /* file name for edior */
	gpointer element; /* pointer indicated textarea */
} EditorInfo;

static gchar *label_color[KZ_TAB_LABEL_N_STATE];

static void kz_actions_popup_append_tablist_menuitem (KzWindow *kz, GtkWidget *tablist_menu);

static void
open_location (GtkAction *action, KzWindow *kz, LocationType location, WindowType window)
{
	const KzEmbedEventMouse *event;
	const gchar *uri = NULL;

	g_return_if_fail(KZ_IS_WINDOW(kz));

	event = kz_window_get_mouse_event_info(kz);
	g_return_if_fail(event);

	switch (location) {
	case LOCATION_LINK:
		uri = event->cinfo.link;
		break;
	case LOCATION_IMAGE:
		uri = event->cinfo.img;
		break;
	case LOCATION_FRAME:
		uri = event->cinfo.frame_src;
		break;
	default:
		g_return_if_reached();
		break;
	}

	if (!uri) return;

	switch (window) {
	case CURRENT_TAB:
		kz_window_load_url(kz, uri);
		break;
	case NEW_TAB:
		kz_window_open_new_tab_with_parent(kz, uri,
						   GTK_WIDGET(KZ_WINDOW_CURRENT_WEB(kz)));
		break;
	case NEW_WINDOW:
	{
		GtkWidget *widget = KZ_CREATE_NEW_WINDOW(uri);
		gtk_widget_show(widget);
		break;
	}
	default:
		g_return_if_reached();
		break;
	}
}

static void
act_popup_open (GtkAction *action, KzWindow *kz)
{
	open_location(action, kz, LOCATION_LINK, CURRENT_TAB);
}

static void
act_popup_open_in_new_tab (GtkAction *action, KzWindow *kz)
{
	open_location(action, kz, LOCATION_LINK, NEW_TAB);
}

static void
act_popup_open_in_new_win (GtkAction *action, KzWindow *kz)
{
	open_location(action, kz, LOCATION_LINK, NEW_WINDOW);
}

static void
act_popup_copy_link_location (GtkAction *action, KzWindow *kz)
{
	const KzEmbedEventMouse *event;

	g_return_if_fail(KZ_IS_WINDOW(kz));

	event = kz_window_get_mouse_event_info(kz);
	g_return_if_fail(event);

	gtkutil_copy_text(event->cinfo.link);
}

static void
act_popup_open_image (GtkAction *action, KzWindow *kz)
{
	open_location(action, kz, LOCATION_IMAGE, CURRENT_TAB);
}

static void
act_popup_open_image_in_new_tab (GtkAction *action, KzWindow *kz)
{
	open_location(action, kz, LOCATION_IMAGE, NEW_TAB);
}

static void
act_popup_open_image_in_new_win (GtkAction *action, KzWindow *kz)
{
	open_location(action, kz, LOCATION_IMAGE, NEW_WINDOW);
}

static void
act_popup_save_link (GtkAction *action, KzWindow *kz)
{
	const KzEmbedEventMouse *event;
	const gchar *uri = NULL;

	g_return_if_fail(KZ_IS_WINDOW(kz));

	event = kz_window_get_mouse_event_info(kz);
	g_return_if_fail(event);

	uri = event->cinfo.link;
	kz_actions_download_open_save_dialog(GTK_WINDOW(kz), uri, FALSE);
}

static void
act_popup_save_image (GtkAction *action, KzWindow *kz)
{
	const KzEmbedEventMouse *event;
	const gchar *uri = NULL;

	g_return_if_fail(KZ_IS_WINDOW(kz));

	event = kz_window_get_mouse_event_info(kz);
	g_return_if_fail(event);

	uri = event->cinfo.img;
	kz_actions_download_open_save_dialog(GTK_WINDOW(kz), uri, FALSE);
}

static void
act_popup_copy_image_location (GtkAction *action, KzWindow *kz)
{
	const KzEmbedEventMouse *event;

	g_return_if_fail(KZ_IS_WINDOW(kz));

	event = kz_window_get_mouse_event_info(kz);
	g_return_if_fail(event);

	gtkutil_copy_text(event->cinfo.img);
}

static void
act_popup_open_frame (GtkAction *action, KzWindow *kz)
{
	open_location(action, kz, LOCATION_FRAME, CURRENT_TAB);
}

static void
cb_web_changed (KzWeb *web, EditorInfo *einfo)
{
	g_return_if_fail(KZ_IS_WEB(web));
	g_return_if_fail(einfo);

	g_signal_handlers_disconnect_by_func(web,
					     G_CALLBACK(cb_web_changed),
					     einfo);
	if (!einfo) return;

	if (einfo->filename)
		g_free(einfo->filename);
	einfo->filename = NULL;
	if (einfo->kzweb)
		g_object_unref(einfo->kzweb);
	einfo->kzweb  = NULL;
	einfo->element  = NULL;
}

static void
cb_editor_exit (GPid pid, gint status, gpointer data)
{
	gchar *text;
	gsize size;
	EditorInfo *einfo;
	
	/* close editor process */
	g_spawn_close_pid(pid);

	if (!data) return;

	einfo = (EditorInfo*)data;
	if (einfo->kzweb)
	{
		g_signal_handlers_disconnect_by_func(einfo->kzweb,
						     G_CALLBACK(cb_web_changed),
						     einfo);
	}

	if (einfo->filename)
	{
		/* get text from temporary file */
		gboolean ret;
		ret = g_file_get_contents(einfo->filename, &text, &size, NULL);
		/* set text into textarea */
		if (ret)
		{
			if (KZ_WEB(einfo->kzweb) && einfo->element)
			{
				kz_web_set_text_into_textarea(einfo->kzweb,
								einfo->element,
								text);
			}
			g_free(text);
		}

		g_free(einfo->filename);
		einfo->filename = NULL;
	}
	
	if (einfo->kzweb)
	{
		g_object_unref(einfo->kzweb);
	}
	einfo->kzweb  = NULL;
	einfo->element  = NULL;
	
	g_free(einfo);
	einfo = NULL;
}


static void
act_popup_launch_editor (GtkAction *action, KzWindow *kz)
{
	const KzEmbedEventMouse *event;
	KzWeb *web;
	GPid pid;
	GSpawnFlags flags;
	gint argc;
	gchar **argv = NULL;
	gchar *editor_command, *command, *text;
	EditorInfo *einfo = NULL;
	
	g_return_if_fail(KZ_IS_WINDOW(kz));
	web = KZ_WINDOW_CURRENT_WEB(kz);
	if (!web)
		return;

	event = kz_window_get_mouse_event_info(kz);
	g_return_if_fail(event);

	editor_command = KZ_CONF_GET_STR("Global", "editor_command");
	if (!editor_command)
		return;

	if (event->cinfo.context & KZ_CONTEXT_TEXTAREA)
	{
		einfo = g_new0(EditorInfo, 1);
		einfo->kzweb  = g_object_ref(web);
		einfo->element  = event->cinfo.element;
		text = kz_web_get_text_from_textarea(web,
						       einfo->element);
		/* text in textare store in temporary file */
		if (text)
		{
			ssize_t size;
			gint fd = g_file_open_tmp("kzXXXXXX",
						  &einfo->filename,
						  NULL);
			size = write(fd, text, strlen(text));
			close(fd);
			g_free(text);
		}

		command = g_strdup_printf(editor_command, einfo->filename);
	}
	else
	{
		command = g_strdup_printf(editor_command, "");
	}
	
	/* */
	g_signal_connect(web, "kz-net-start",
			 G_CALLBACK(cb_web_changed), einfo);
	g_signal_connect(web, "destroy",
			 G_CALLBACK(cb_web_changed), einfo);
	/* launch editor */
	g_shell_parse_argv(command,
			   &argc,
			   &argv,
			   NULL);

	flags = G_SPAWN_SEARCH_PATH |
		G_SPAWN_DO_NOT_REAP_CHILD;
	g_spawn_async(NULL,
		      argv,
		      NULL,
		      flags,
		      NULL,
		      NULL,
		      &pid,
		      NULL);
	g_free(editor_command);
	g_free(command);
	g_strfreev(argv);

	g_child_watch_add(pid,
			  cb_editor_exit,
			  einfo);

}

static void
cb_popup_menu_hide (void)
{
	gtk_main_quit();
}

static void
cb_tablist_menuitem_activate (GtkWidget *menuitem, KzWindow *kz)
{
	gint page_num;
	GtkWidget *widget = g_object_get_data(G_OBJECT(menuitem),
					      KZ_ACTIONS_POPUP_TAB_KEY);

	page_num = kz_notebook_page_num(KZ_NOTEBOOK(kz->notebook),
					GTK_WIDGET(widget));

	kz_notebook_set_current_page(KZ_NOTEBOOK(kz->notebook), page_num);
}


static void
act_popup_tab_list (GtkAction *action, KzWindow *kz)
{
	GtkWidget *popup_menu = NULL;
	GList *children, *node;

	popup_menu = gtk_ui_manager_get_widget(kz->menu_merge,
					       "/TabListPopup");
	if (!popup_menu) return;

	/* remove previous menu item */
	children = g_list_copy(GTK_MENU_SHELL(popup_menu)->children);
	
	for (node = children; node; node = g_list_next(node))
	{
		GtkWidget *menuitem = node->data;
		gtk_widget_destroy(menuitem);
	}
	g_list_free(children);

	kz_actions_popup_append_tablist_menuitem(kz, popup_menu);
	
	g_signal_connect(popup_menu, "hide",
			 G_CALLBACK(cb_popup_menu_hide), kz);
	gtk_menu_popup(GTK_MENU(popup_menu), NULL, NULL,
		       NULL, NULL, 0, 0);
	gtk_main();

	g_signal_handlers_disconnect_by_func(popup_menu,
					     G_CALLBACK(cb_popup_menu_hide), kz);
}

static GtkActionEntry kz_actions_popup[] =
{
        /* Toplevel */

	{"OpenLink",            NULL, N_("_Open"),
	 NULL, N_("Open link"), G_CALLBACK(act_popup_open)},
	{"OpenLinkInNewTab",    NULL, N_("Open in new _tab"),
	 NULL, N_("Open link in a new tab"), G_CALLBACK(act_popup_open_in_new_tab)},
	{"OpenLinkInNewWindow", KZ_STOCK_OPEN_LINK_WINDOW, N_("Open in new _window"),
	 NULL, N_("Open link in a new window"), G_CALLBACK(act_popup_open_in_new_win)},
	{"CopyLinkLocation", KZ_STOCK_COPY_URL, N_("Copy _link location"),
	 NULL, N_("Copy the location of the link"), G_CALLBACK(act_popup_copy_link_location)},
	{"SaveLink", KZ_STOCK_SAVE_LINK, N_("Save lin_k to disk"),
	 NULL, N_("Save the object to disk"), G_CALLBACK(act_popup_save_link)},

	{"OpenImage",           NULL, N_("Open _image"),
	 NULL, N_("Open the image"), G_CALLBACK(act_popup_open_image)},
	{"OpenImageInNewTab",   NULL, N_("Open image in new ta_b"),
	 NULL, N_("Open the image in a new tab"), G_CALLBACK(act_popup_open_image_in_new_tab)},
	{"OpenImageInNewWindow",KZ_STOCK_OPEN_IMAGE_WINDOW, N_("Open image in _new window"),
	 NULL, N_("Open the image in a new window"), G_CALLBACK(act_popup_open_image_in_new_win)},
	{"CopyImageLocation", KZ_STOCK_COPY_IMAGE_URL, N_("Copy image l_ocation"),
	 NULL, N_("Copy the location of the image"), G_CALLBACK(act_popup_copy_image_location)},
	{"SaveImage",           NULL, N_("Sa_ve image as"),
	 NULL, N_("Save the image to disk"), G_CALLBACK(act_popup_save_image)},

	{"OpenThisFrame",        NULL, N_("Open this _frame"),
	NULL, N_("Open the frame in the current tab"),  G_CALLBACK(act_popup_open_frame)},

	{"LaunchEditor",         GTK_STOCK_EDIT, N_("_Launch Editor"),
	 NULL, N_("Launch external editor"), G_CALLBACK(act_popup_launch_editor)},
	{"PopupTabList",         NULL, N_("_Popup TabList"),
	 NULL, N_("Display tab list"), G_CALLBACK(act_popup_tab_list)},

	{"StockEncodingMenu", NULL, N_("_Encoding"), NULL, NULL, NULL},
	{"StockTabList",      NULL, N_("_TabList"),  NULL, NULL, NULL},
	{"StockOpenSmartBookmark",      NULL, N_("Open Smartbookmark by selected text"),  NULL, NULL, NULL},
};

static const gint kz_actions_popup_len = G_N_ELEMENTS(kz_actions_popup);


GtkActionGroup *
kz_actions_popup_create_group (KzWindow *kz)
{
	GtkActionGroup *action_group;

	action_group = gtk_action_group_new("KzWindowPopup");

	gtk_action_group_set_translation_domain(action_group, NULL);

	gtk_action_group_add_actions(action_group,
				     kz_actions_popup,
				     kz_actions_popup_len,
				     kz);

	return action_group;
}

static GHashTable *popup_menu_table = NULL;

static void
cb_popup_destroy (GtkWidget *extra_menu)
{
	if (popup_menu_table) 
	{
		g_hash_table_remove(popup_menu_table, extra_menu);
	}
	return;
}

static gboolean 
cb_encoding_menuitem_destroy (GtkWidget *menuitem, gchar *encoding)
{
	g_return_val_if_fail (GTK_CHECK_MENU_ITEM(menuitem), FALSE);
	
	if (encoding)
		g_free(encoding);
	
	g_object_set_data(G_OBJECT(menuitem), 
			  KZ_ACTIONS_POPUP_LANGUAGE_KEY,
			  NULL);
	
	return FALSE;
}

static void
cb_encoding_menuitem_activate (GtkWidget *menuitem, KzWindow *kz)
{
	KzWeb *web = KZ_WINDOW_CURRENT_WEB(kz);

	if (GTK_CHECK_MENU_ITEM(menuitem)->active && web)
	{
		const gchar* code
			= g_object_get_data(G_OBJECT(menuitem),
					    KZ_ACTIONS_POPUP_LANGUAGE_KEY);
		GtkAction *action;

		kz_web_set_encoding(web, code);

		action = gtk_action_group_get_action(kz->actions, "Reload");

		gtk_action_activate(action);
	}
}

static GtkWidget *
create_lang_menu_item (KzWindow *kz, KzXMLNode *node,
		       GSList **group, const gchar *current_encoding,
		       gboolean forced)
{
	GtkWidget *menuitem = NULL;
	const gchar *label;

	if (!kz_xml_node_is_element(node)) return NULL;

	label = kz_xml_node_get_attr(node, "label");
	g_return_val_if_fail(label, NULL);

	if (kz_xml_node_name_is(node, "group"))
	{
		GtkWidget *submenu;
		KzXMLNode *child_node;

		menuitem = gtk_menu_item_new_with_label(label);
		submenu = gtk_menu_new();
		gtk_menu_item_set_submenu(GTK_MENU_ITEM(menuitem), submenu);
		gtk_widget_show(submenu);

		for (child_node = kz_xml_node_first_child(node);
		     child_node;
		     child_node = kz_xml_node_next(child_node))
		{
			GtkWidget *child_menuitem;

			child_menuitem = create_lang_menu_item
				(kz, child_node, group,
				 current_encoding, forced);
			if (!child_menuitem) continue;

			gtk_menu_shell_append(GTK_MENU_SHELL(submenu),
					      child_menuitem);
			gtk_widget_show(child_menuitem);
		}
	}
	else if (kz_xml_node_name_is(node, "encoding"))
	{
		gchar *encoding;

		encoding = g_strdup(kz_xml_node_get_attr(node, "name"));

		menuitem = gtk_radio_menu_item_new_with_label(*group, _(label));
		g_object_set_data(G_OBJECT(menuitem),
				  KZ_ACTIONS_POPUP_LANGUAGE_KEY,
				  (gpointer) encoding);
		g_signal_connect(menuitem, "activate",
				 G_CALLBACK(cb_encoding_menuitem_activate), kz);
		g_signal_connect(menuitem, "destroy",
				 G_CALLBACK(cb_encoding_menuitem_destroy), encoding);

		if (forced && current_encoding &&
		    !strcmp(current_encoding, encoding))
		{
			gtk_check_menu_item_set_active
				(GTK_CHECK_MENU_ITEM(menuitem),
				 TRUE);
		}
		*group = gtk_radio_menu_item_get_group
				(GTK_RADIO_MENU_ITEM(menuitem));
	}
	else
	{
		/* warning? */
	}

	return menuitem;
}


static void
kz_actions_popup_append_encoding_menuitem (KzWindow *kz,
					   GtkMenuItem *encoding_menu)
{
	GtkWidget *encoding_submenu;
	GtkWidget *menuitem;
	GSList *group = NULL;
	KzWeb *web = KZ_WINDOW_CURRENT_WEB(kz);
	gchar *encodings_xml;
	gchar *current_encoding = NULL;
	gboolean forced = FALSE;
	KzXML *xml;
	KzXMLNode *node;

	if (!popup_menu_table)
	{
		popup_menu_table = g_hash_table_new(g_direct_hash,
						    g_direct_equal);
	}

	encoding_submenu = g_hash_table_lookup(popup_menu_table, encoding_menu);
	if (encoding_submenu) return;

	/* append encodings menuitem */
	encoding_submenu = gtk_menu_new();

	/* get current charset */
	if(web)
	{
		kz_web_get_encoding(web,
				      &current_encoding, &forced);
	}

	menuitem = gtk_radio_menu_item_new_with_label(group, _("Auto"));
	if(!forced) {
		gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menuitem),
					       TRUE);
	}

	group = gtk_radio_menu_item_get_group(GTK_RADIO_MENU_ITEM(menuitem));
	g_object_set_data(G_OBJECT(menuitem),
			  KZ_ACTIONS_POPUP_LANGUAGE_KEY, "");

	g_signal_connect(menuitem, "activate",
			 G_CALLBACK(cb_encoding_menuitem_activate), kz);

	gtk_menu_shell_append(GTK_MENU_SHELL(encoding_submenu), menuitem);
	gtk_widget_show(menuitem);

	/* separator */
	menuitem = gtk_separator_menu_item_new();
	gtk_menu_shell_append(GTK_MENU_SHELL(encoding_submenu), menuitem);
	gtk_widget_show(menuitem);

	xml = kz_xml_new();
	encodings_xml = g_build_filename(KZ_GET_SYSTEM_CONFIG_DIR,
					 "mozilla",
					 "encodings.xml",
					 NULL);
	kz_xml_load(xml, encodings_xml);
	g_free(encodings_xml);
	node = kz_xml_get_root_element(xml);
	if (node && kz_xml_node_name_is(node, "encodings"))
	{
		node = kz_xml_node_first_child(node);
		for (; node; node = kz_xml_node_next(node))
		{
			menuitem = create_lang_menu_item(kz, node, &group,
							 current_encoding,
							 forced);
			if (!menuitem) continue;

			gtk_menu_shell_append(GTK_MENU_SHELL(encoding_submenu),
					      menuitem);
			gtk_widget_show(menuitem);
		}
	}
	g_object_unref(xml);

	gtk_menu_item_set_submenu(GTK_MENU_ITEM(encoding_menu),
				  encoding_submenu);

	g_free(current_encoding);

	/* reference */
	g_hash_table_insert(popup_menu_table, encoding_menu, encoding_submenu);
	g_signal_connect(encoding_menu, "destroy",
			 G_CALLBACK(cb_popup_destroy), NULL);
}


static void
kz_actions_popup_append_tablist_menuitem (KzWindow *kz, GtkWidget *tablist_menu)
{
	gint i;
	GtkWidget *tablist_submenu;
	gint current_page_num;
	KzFavicon *kzfav = KZ_GET_FAVICON;
	gchar *color = NULL;
	const gint num = kz_notebook_get_n_pages(KZ_NOTEBOOK(kz->notebook));

	/* label color */
	color = KZ_CONF_GET_STR("Tab" , "normal_color");
	if (!color)
		color = g_strdup("#000000");

	if (label_color[KZ_TAB_LABEL_STATE_NORMAL])
		g_free(label_color[KZ_TAB_LABEL_STATE_NORMAL]);
	label_color[KZ_TAB_LABEL_STATE_NORMAL] = g_strdup(color);
	g_free(color);

	color = KZ_CONF_GET_STR("Tab" , "loading_color");
	if (!color)
		color = g_strdup("#ff0000");
	if (label_color[KZ_TAB_LABEL_STATE_LOADING])
		g_free(label_color[KZ_TAB_LABEL_STATE_LOADING]);
	label_color[KZ_TAB_LABEL_STATE_LOADING] = g_strdup(color);
	g_free(color);

	color = KZ_CONF_GET_STR("Tab" , "loaded_color");
	if (!color)
		color = g_strdup("#22aa44");
	if (label_color[KZ_TAB_LABEL_STATE_LOADED])
		g_free(label_color[KZ_TAB_LABEL_STATE_LOADED]);
	label_color[KZ_TAB_LABEL_STATE_LOADED] = g_strdup(color);
	g_free(color);

	if (GTK_IS_MENU_ITEM(tablist_menu))
	{
		if (!popup_menu_table)
		{
			popup_menu_table = g_hash_table_new(g_direct_hash,
							    g_direct_equal);
		}

		tablist_submenu = g_hash_table_lookup(popup_menu_table,
						      tablist_menu);

		if (tablist_submenu)
		{
			gtk_menu_item_set_submenu(GTK_MENU_ITEM(tablist_menu), NULL);
		}
        	/* append tablist menuitem */
		tablist_submenu = gtk_menu_new();
	}
	else
	{
		tablist_submenu = tablist_menu;
	}

	current_page_num = kz_notebook_get_current_page(KZ_NOTEBOOK(kz->notebook));

	for (i = 0; i < num; i++)
	{
		KzWeb *kzweb = KZ_WINDOW_NTH_WEB(kz, i);
		GtkWidget *favicon;
		gchar *title, *escaped, *markup_title;
		GtkWidget *menuitem;
		KzTabLabel *tab;
		KzTabLabelState state;

		if (!kzweb)
                        continue;
			
		tab = kz_window_get_tab_label(kz, kzweb);
		state = kz_tab_label_get_state(tab);
		title = kz_web_ensure_title(kzweb);
		escaped = g_markup_escape_text(title,
					       strlen(title));
		menuitem = gtk_image_menu_item_new_with_label(title);

		if (i == current_page_num)
		{
			markup_title = g_strdup_printf("<b>%s</b>",
						       escaped);
		}
		else
		{
			markup_title = g_strdup_printf("<span foreground=\"%s\">%s</span>",
						       label_color[state],
						       escaped);
		}

		gtk_label_set_markup(GTK_LABEL(gtk_bin_get_child(GTK_BIN(menuitem))),
				     markup_title);
		g_free(markup_title);
		g_free(escaped);
		
		/* favicon */
		favicon = kz_favicon_get_widget(kzfav,
						kz_web_get_location(kzweb),
						KZ_ICON_SIZE_BOOKMARK_MENU);
		if (favicon)
		{
			gtk_widget_show(favicon);
			gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menuitem),
						      favicon);
		}

		g_object_set_data (G_OBJECT(menuitem), KZ_ACTIONS_POPUP_TAB_KEY, kzweb);

		g_signal_connect(menuitem, "activate",
				 G_CALLBACK(cb_tablist_menuitem_activate), kz);
		gtk_menu_shell_append(GTK_MENU_SHELL(tablist_submenu), menuitem);
		gtk_widget_show(menuitem);
		g_free(title);
	}
	if (GTK_IS_MENU_ITEM(tablist_menu))
	{
		gtk_menu_item_set_submenu(GTK_MENU_ITEM(tablist_menu),
					  tablist_submenu);

        	/* reference */
		g_hash_table_insert(popup_menu_table,
				    tablist_menu,
				    tablist_submenu);
		g_signal_connect(tablist_menu, "destroy",
				 G_CALLBACK(cb_popup_destroy), NULL);
	}
	return;
}

#define GET_MENU(kz, path) \
	(gtk_ui_manager_get_widget(kz->menu_merge, path))


void
kz_actions_popup_menu_modal (KzWindow *kz, guint button, guint time)
{
	GtkWidget *popup_menu = NULL;
	GtkWidget *extra_menu = NULL;
	const KzEmbedEventMouse *event;
	gboolean is_selection, is_doc, is_link, is_image, is_input, is_frame;
	gchar path[64] = {0};
	gchar extra_menu_path[64] = {0};

	event = kz_window_get_mouse_event_info(kz);
	if (!event) return;

	is_selection = event->cinfo.context & KZ_CONTEXT_SELECTION;
	is_doc       = event->cinfo.context & KZ_CONTEXT_DOCUMENT;
	is_link      = event->cinfo.context & KZ_CONTEXT_LINK;
	is_image     = event->cinfo.context & KZ_CONTEXT_IMAGE;
	is_input     = event->cinfo.context & KZ_CONTEXT_INPUT;
	is_frame     = event->cinfo.context & KZ_CONTEXT_FRAME;

#if 0
	if (is_selection)
		/*
		 * FIXME!! We should merge this menu items to other context's
		 * menu.
		 */
		popup_menu = GET_MENU(kz, "/SelectionPopup");
	else
#endif
	if (is_doc)
	{
		if (is_frame)
			g_snprintf(path, sizeof(path), "/DocumentPopupinFrame");
		else
			g_snprintf(path, sizeof(path), "/DocumentPopup");
	}
	if (is_link && is_image)
		g_snprintf(path, sizeof(path), "/LinkImagePopup");
	else if (is_link)
		g_snprintf(path, sizeof(path), "/LinkPopup");
	else if (is_image)
		g_snprintf(path, sizeof(path), "/ImagePopup");
	else if (is_input)
		g_snprintf(path, sizeof(path), "/InputPopup");

	if (!*path) return;

	popup_menu = GET_MENU(kz, path);
	if (!popup_menu) return;

	if (is_input) {
		gtkutil_append_im_menuitem(GTK_MENU_SHELL(popup_menu));
	}

        /* add copy in user format */
	g_snprintf(extra_menu_path,
		   sizeof(extra_menu_path), "%s/CopyInUserFormat", path);

	extra_menu = GET_MENU(kz, extra_menu_path);
	if (extra_menu)
	{
		KzTabLabel *kztab;
		gint current_page;

		current_page = kz_notebook_get_current_page(KZ_NOTEBOOK(kz->notebook));
		kztab = kz_notebook_get_nth_tab_label(KZ_NOTEBOOK(kz->notebook), current_page);
		kz_actions_dynamic_append_copy_in_user_format_menuitem
			(kztab, GTK_MENU_ITEM(extra_menu));
	}

        /* add encoding menu */
	g_snprintf(extra_menu_path,
		   sizeof(extra_menu_path), "%s/EncodingMenu", path);

	extra_menu = GET_MENU(kz, extra_menu_path);
	if (extra_menu)
	{
		kz_actions_popup_append_encoding_menuitem
			(kz, GTK_MENU_ITEM(extra_menu));
	}

        /* add tablist */
	g_snprintf(extra_menu_path,
		   sizeof(extra_menu_path), "%s/TabList", path);
	extra_menu = GET_MENU(kz, extra_menu_path);
	if (extra_menu)
	{
		kz_actions_popup_append_tablist_menuitem(kz, extra_menu);
	}

        /* add smart bookmark menu*/
	g_snprintf(extra_menu_path,
		   sizeof(extra_menu_path), "%s/OpenSmartBookmark", path);
	extra_menu = GET_MENU(kz, extra_menu_path);
	if (extra_menu)
	{
		kz_actions_dynamic_append_open_smart_bookmark_menuitem
			(kz, GTK_MENU_ITEM(extra_menu));
	}

	g_signal_connect(popup_menu, "hide",
			 G_CALLBACK(cb_popup_menu_hide), kz);
	gtk_menu_popup(GTK_MENU(popup_menu), NULL, NULL,
		       NULL, NULL, 0, time);
	gtk_main();

	g_signal_handlers_disconnect_by_func(popup_menu,
					     G_CALLBACK(cb_popup_menu_hide), kz);
}
