/* -*- 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-embed.h"
#include "kz-favicon.h"
#include "kz-xml.h"
#include "kz-actions-dynamic.h"
#include "kz-icons.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
{
	KzEmbed *kzembed;
	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,
						   KZ_WINDOW_CURRENT_PAGE(kz));
		break;
	case NEW_WINDOW:
	{
		GtkWidget *widget = kz_app_create_new_window(kz_app, 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_embed_changed (KzEmbed *embed, EditorInfo *einfo)
{
	g_return_if_fail(KZ_IS_EMBED(embed));
	g_return_if_fail(einfo);

	g_signal_handlers_disconnect_by_func(embed,
			 		     G_CALLBACK(cb_embed_changed),
					     einfo);
	if (!einfo) return;

	if (einfo->filename)
		g_free(einfo->filename);
	einfo->filename = NULL;
	if (einfo->kzembed)
		g_object_unref(einfo->kzembed);
	einfo->kzembed  = 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->kzembed)
	{
		g_signal_handlers_disconnect_by_func(einfo->kzembed,
			 		     G_CALLBACK(cb_embed_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_EMBED(einfo->kzembed) && einfo->element)
			{
				kz_embed_set_text_into_textarea(einfo->kzembed,
								einfo->element,
								text);
			}
			g_free(text);
		}

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


static void
act_popup_launch_editor (GtkAction *action, KzWindow *kz)
{
	const KzEmbedEventMouse *event;
	GtkWidget *widget;

	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));
	widget = KZ_WINDOW_CURRENT_PAGE(kz);
	g_return_if_fail(KZ_EMBED(widget));

	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->kzembed  = g_object_ref(KZ_EMBED(widget));
		einfo->element  = event->cinfo.element;
		text = kz_embed_get_text_from_textarea(KZ_EMBED(widget),
						       einfo->element);
		/* text in textare store in temporary file */
		if (text)
		{
			gint fd = g_file_open_tmp("kzXXXXXX",
						  &einfo->filename,
						  NULL);
			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(widget, "kz-net-start",
			 G_CALLBACK(cb_embed_changed), einfo);
	g_signal_connect(widget, "destroy",
			 G_CALLBACK(cb_embed_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 = gtk_notebook_page_num(GTK_NOTEBOOK(kz->notebook),
					 GTK_WIDGET(widget));

	gtk_notebook_set_current_page(GTK_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)
{
	GtkWidget *widget = KZ_WINDOW_CURRENT_PAGE(kz);

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

		kz_embed_set_encoding(KZ_EMBED(widget), code);

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

		gtk_action_activate(action);
	}
	return;
}

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;
	GtkWidget *page = KZ_WINDOW_CURRENT_PAGE(kz);
	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(KZ_EMBED(page))
	{
		kz_embed_get_encoding(KZ_EMBED(page),
				      &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();
	kz_xml_load(xml, KZ_SYSCONFDIR "/mozilla/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(G_OBJECT(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;
	const gint num = gtk_notebook_get_n_pages(GTK_NOTEBOOK(kz->notebook));
	GtkWidget *tablist_submenu;
	GtkWidget *page;
	gint current_page_num;
	KzFavicon *kzfav = KZ_GET_FAVICON;
	gchar *color = NULL;

	/* 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_remove_submenu(GTK_MENU_ITEM(tablist_menu));
		}
        	/* append tablist menuitem */
		tablist_submenu = gtk_menu_new();
	}
	else
	{
		tablist_submenu = tablist_menu;
	}

	page = KZ_WINDOW_CURRENT_PAGE(kz);
	current_page_num = gtk_notebook_page_num(GTK_NOTEBOOK(kz->notebook),
						 GTK_WIDGET(page));

	for (i = 0; i < num; i++)
	{
		KzEmbed *kzembed = KZ_EMBED(KZ_WINDOW_NTH_PAGE(kz, i));
		GtkWidget *favicon;

		if (KZ_EMBED(kzembed))
		{
			gchar *title, *escaped, *markup_title;
			GtkWidget *menuitem;
			GtkWidget *tab;
			KzTabLabelState state;
			
			tab = kz_window_get_tab_label(kz, GTK_WIDGET(kzembed));
			state = kz_tab_label_get_state(KZ_TAB_LABEL(tab));
			title = kz_embed_ensure_title(kzembed);
			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_embed_get_location(kzembed),
							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, kzembed);

			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;
		kztab = KZ_TAB_LABEL(kz_window_get_tab_label(kz, KZ_WINDOW_CURRENT_PAGE(kz)));
		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);
}
