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

/*
 *  Copyright (C) 2003 Hiroyuki Ikezoe
 *  Copyright (C) 2003 Takuro Ashie <ashie@homa.ne.jp>
 *
 *  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 "gtk-utils.h"
#include <string.h>
#include "intl.h"

#define ICON_TRANS 192

/**
 * menu_position_under_widget:
 * this function from galeon-1.2.7
 */
void
gtkutil_menu_position_under_widget (GtkMenu *menu, gint *x, gint *y,
				    gboolean *push_in, gpointer user_data)
{
	GtkWidget *w = GTK_WIDGET(user_data);
	gint wheight;
	gint wx, wy;

	gdk_window_get_origin(w->window, x, y);
	wheight = w->requisition.height;
	wx = w->allocation.x;
	wy = w->allocation.y;
	
	*y = *y + wy + wheight;
	*x = *x + wx;
}


static void
tree_selection_foreach_get_path_func(GtkTreeModel *model,
				     GtkTreePath *path, GtkTreeIter *iter,
				     gpointer data)
{
	GList **list;

	g_return_if_fail(data);

	list = data;
	*list = g_list_append(*list, gtk_tree_path_copy(path));
}

GList *
gtkutil_tree_selection_get_selected_rows(GtkTreeSelection *selection,
					 GtkTreeModel **model)
{
#if (GTK_MAJOR_VERSON >= 2) && (GTK_MINOR_VERSION >= 2)
	return gtk_tree_selection_get_selected_rows(selection, model);
#else /* (GTK_MAJOR_VERSON >= 2) && (GTK_MINOR_VERSION >= 2) */
	GtkTreeView *tree_view;
	GList *list = NULL;

	g_return_val_if_fail(GTK_IS_TREE_SELECTION(selection), NULL);

	tree_view = gtk_tree_selection_get_tree_view(selection);

	if (model != NULL)
		*model = gtk_tree_view_get_model(tree_view);

	gtk_tree_selection_selected_foreach(selection,
					    tree_selection_foreach_get_path_func,
					    &list);

	return list;
#endif /* (GTK_MAJOR_VERSON >= 2) && (GTK_MINOR_VERSION >= 2) */
}

GList *
gtkutil_tree_selection_get_selected_references(GtkTreeSelection *selection,
					       GtkTreeModel **tree_model)
{
	GtkTreeModel *model;
	GList *list, *ref_list = NULL;

	g_return_val_if_fail(GTK_IS_TREE_SELECTION(selection), NULL);

	list = gtkutil_tree_selection_get_selected_rows(selection, &model);

	for (; list; list = g_list_next(list)) {
		GtkTreeRowReference *ref = NULL;
		if (list->data != NULL)
			ref = gtk_tree_row_reference_new(model, list->data);
		if (ref != NULL)
			ref_list = g_list_append(ref_list, ref);
	}

	if (list) {
		g_list_foreach(list, (GFunc) gtk_tree_path_free, NULL);
		g_list_free(list);
	}

	if (tree_model != NULL)
		*tree_model = model;

	return ref_list;
}

/*
 *  These codes are aken from Gtk+-2.2.1 (gtk/gtkliststore.c).
 *  Copyright (C) 2000  Red Hat, Inc.,  Jonathan Blandford <jrb@redhat.com>
 */
#define G_SLIST(x) ((GSList *) x)
#define GTK_LIST_STORE_IS_SORTED(list) (GTK_LIST_STORE (list)->sort_column_id != -2)
#define VALID_ITER(iter, list_store) (iter!= NULL && iter->user_data != NULL && list_store->stamp == iter->stamp)

void
gtkutil_list_store_swap(GtkListStore *store, GtkTreeIter  *a, GtkTreeIter  *b)
{
#if (GTK_MAJOR_VERSON >= 2) && (GTK_MINOR_VERSION >= 2)
	gtk_list_store_swap(store, a, b);
#else /* (GTK_MAJOR_VERSON >= 2) && (GTK_MINOR_VERSION >= 2) */
	GSList *i, *prev_a = NULL, *prev_b = NULL;
	gint j, a_count = 0, b_count = 0, *order;
	GtkTreePath *path;

	g_return_if_fail(GTK_IS_LIST_STORE(store));
	g_return_if_fail(!GTK_LIST_STORE_IS_SORTED(store));
	g_return_if_fail(VALID_ITER(a, store));
	g_return_if_fail(VALID_ITER(b, store));

	if (a->user_data == b->user_data)
		return;

	if (a->user_data == store->root)
		prev_a = NULL;
	else {
		for (i = store->root; i; i = i->next, a_count++)
			if (i->next == a->user_data) {
				prev_a = i;
				break;
			}
		a_count++;
	}

	if (b->user_data == store->root)
		prev_b = NULL;
	else {
		for (i = store->root; i; i = i->next, b_count++)
			if (i->next == b->user_data) {
				prev_b = i;
				break;
			}
		b_count++;
	}

	if (!prev_a)
		store->root = b->user_data;
	else
		prev_a->next = b->user_data;

	if (!prev_b)
		store->root = a->user_data;
	else
		prev_b->next = a->user_data;

	/* think a_next inspead of a_prev here ... */
	prev_a = G_SLIST(a->user_data)->next;
	prev_b = G_SLIST(b->user_data)->next;

	G_SLIST(a->user_data)->next = prev_b;
	G_SLIST(b->user_data)->next = prev_a;

	/* update tail if needed */
	if (!G_SLIST(a->user_data)->next)
		store->tail = G_SLIST(a->user_data);
	else if (! G_SLIST(b->user_data)->next)
		store->tail = G_SLIST(b->user_data);

	/* emit signal */
	order = g_new(gint, store->length);
	for (j = 0; j < store->length; j++)
		if (j == a_count)
			order[j] = b_count;
		else if (j == b_count)
			order[j] = a_count;
		else
			order[j] = j;

	path = gtk_tree_path_new();
	gtk_tree_model_rows_reordered(GTK_TREE_MODEL (store),
				      path, NULL, order);
	gtk_tree_path_free(path);
	g_free(order);
#endif /* (GTK_MAJOR_VERSON >= 2) && (GTK_MINOR_VERSION >= 2) */
}

void
gtkutil_copy_text (const gchar *text)
{
	if (text && *text)
	{
		GtkClipboard *clipboard = gtk_clipboard_get(GDK_SELECTION_PRIMARY);
		gtk_clipboard_set_text(clipboard, text, strlen(text));
		clipboard = gtk_clipboard_get(GDK_SELECTION_CLIPBOARD);
		gtk_clipboard_set_text(clipboard, text, strlen(text));
	}
}


static GHashTable *popup_menu_table;

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


void
gtkutil_append_im_menuitem (GtkMenuShell *shell)
{
	static GtkIMMulticontext *im_context = NULL;
	GtkWidget *immenu, *menuitem;

	if (!im_context)
		im_context = GTK_IM_MULTICONTEXT(gtk_im_multicontext_new());

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

	menuitem = g_hash_table_lookup(popup_menu_table, shell);
	if (menuitem)
	{
		gtk_menu_item_remove_submenu(GTK_MENU_ITEM(menuitem));
	}
	else
	{
		/* separator */
		menuitem = gtk_separator_menu_item_new();
		gtk_menu_shell_append(shell, menuitem);
		gtk_widget_show(menuitem);

		/* input methods menuitem */
		menuitem = gtk_menu_item_new_with_label(_("Input Methods"));
		gtk_menu_shell_append(shell, menuitem);
		gtk_widget_show(menuitem);

		/* reference */
		g_hash_table_insert(popup_menu_table, shell, menuitem);
		g_signal_connect(G_OBJECT(shell), "destroy",
				 G_CALLBACK(cb_popup_destroy), NULL);
	}

	/* input methods submenu */
	immenu = gtk_menu_new();
	gtk_im_multicontext_append_menuitems
		(im_context, GTK_MENU_SHELL(immenu));
	gtk_menu_item_set_submenu(GTK_MENU_ITEM(menuitem), immenu);
}



void
gtkutil_superpose_pixbuf(GtkWidget *widget, GdkPixbuf *pixbuf, 
			 const gchar *stock_id, GtkIconSize size)
{
	gint width, height;
	GdkPixbuf *orig_pixbuf;

	orig_pixbuf = gtk_widget_render_icon(widget, stock_id, 
					     size,
					     NULL);
	gtk_icon_size_lookup(size, &width, &height);

	if (pixbuf)
	{
		gint x, y;
		GdkPixbuf *scaled_pixbuf, *transparent_pixbuf;
		
		x = width / 2;
		y = width / 2;
		scaled_pixbuf = gdk_pixbuf_scale_simple(orig_pixbuf,
							x, y,
							GDK_INTERP_NEAREST);
		transparent_pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB,
						    TRUE,
						    8,
						    width,
						    height);
		gdk_pixbuf_fill(transparent_pixbuf, 0);
		gdk_pixbuf_composite(pixbuf,
				     transparent_pixbuf,
				     0, 0,
				     width, height,
				     0, 0,
				     1, 1,
				     GDK_INTERP_NEAREST,
				     ICON_TRANS);
		gdk_pixbuf_composite(scaled_pixbuf,
				     transparent_pixbuf,
				     x, y,
				     x, y,
				     x, y,
				     1, 1,
				     GDK_INTERP_NEAREST,
				     255);
				     
		gtk_image_set_from_pixbuf(GTK_IMAGE(widget), transparent_pixbuf);
		g_object_unref(scaled_pixbuf);
	}
	else 
		gtk_image_set_from_pixbuf(GTK_IMAGE(widget), orig_pixbuf);

	g_object_unref(orig_pixbuf);
}
