/* Module for creating a shaped window with text (for desktop icons)
 *
 * Copyright (C) 1998 the Free Software Foundation
 *
 * Author: Federico Mena <federico@nuclecu.unam.mx>
 */

#include <gnome.h>
#include <string.h>
#include "gdesktop.h"
#include "gcache.h"
#include <gdk/gdkx.h>
/* The spacing between the cute little icon and the text */
#define SPACING 2

/*
 * Most of this code was yanked from the gtktooltips module in Gtk+.
 * I have tweaked it a bit for MC's purposes - Federico
 */

struct text_info {
	GList *rows;
	GdkFont *font;
	int width;
	int height;
	int baseline_skip;
};


static void
free_string (gpointer data, gpointer user_data)
{
	if (data)
		g_free (data);
}

static void
text_info_free (struct text_info *ti)
{
	g_list_foreach (ti->rows, free_string, NULL);
	g_list_free (ti->rows);
	g_free (ti);
}

static struct text_info *
layout_text (GtkWidget *widget, char *text)
{
	struct text_info *ti;
	char *row_end, *row_text, *break_pos;
	int i, row_width, window_width;
	size_t len;

	ti = g_new (struct text_info, 1);

	ti->rows = NULL;
	ti->font = widget->style->font;
	ti->width = 0;
	ti->height = 0;

	ti->baseline_skip = ti->font->ascent + ti->font->descent;

	window_width = 0;

	while (*text) {
		row_end = strchr (text, '\n');
		if (!row_end)
			row_end = strchr (text, '\0');

		len = row_end - text + 1;
		row_text = g_new (char, len);
		memcpy (row_text, text, len - 1);
		row_text[len - 1] = '\0';

		/* Adjust the window's width or shorten the row until
		 * it fits in the window.
		 */

		while (1) {
			row_width = gdk_string_width (ti->font, row_text);
			if (!window_width) {
				/* make an initial guess at window's width */

				if (row_width > (gdk_screen_width () / 12))
					window_width = gdk_screen_width () / 12;
				else
					window_width = row_width;
			}

			if (row_width <= window_width)
				break;

			if (strchr (row_text, ' ')) {
				/* the row is currently too wide, but we have
				 * blanks in the row so we can break it into
				 * smaller pieces
				 */

				int avg_width = row_width / strlen (row_text);

				i = window_width;

				if (avg_width != 0)
					i /= avg_width;

				if ((size_t) i >= len)
					i = len - 1;

				break_pos = strchr (row_text + i, ' ');
				if (!break_pos) {
					break_pos = row_text+ i;
					while (*--break_pos != ' ');
				}

				*break_pos = '\0';
			} else {
				/* We can't break this row into any smaller
				 * pieces, so we have no choice but to widen
				 * the window
				 *
				 * For MC, we may want to modify the code above
				 * so that it can also split the string on the
				 * slahes of filenames.
				 */

				window_width = row_width;
				break;
			}
		}

		if (row_width > ti->width)
			ti->width = row_width;

		ti->rows = g_list_append (ti->rows, row_text);
		ti->height += ti->baseline_skip;

		text += strlen (row_text);
		if (!*text)
			break;

		if (text[0] == '\n' && text[1]) {
			/* end of paragraph and there is more text to come */
			ti->rows = g_list_append (ti->rows, NULL);
			ti->height += ti->baseline_skip / 2;
		}

		text++; /* skip blank or newline */
	}

	return ti;
}

static void
paint_text (struct text_info *ti, GdkDrawable *drawable, GdkGC *gc, int x_ofs, int y_ofs)
{
	int y, w;
	GList *item;

	y = y_ofs + ti->font->ascent;

	for (item = ti->rows; item; item = item->next) {
		if (item->data) {
			w = gdk_string_width (ti->font, item->data);
			gdk_draw_string (drawable, ti->font, gc, x_ofs + (ti->width - w) / 2, y, item->data);
			y += ti->baseline_skip;
		} else
			y += ti->baseline_skip / 2;
	}
}

static void
set_window_text (GtkWidget *window, GdkImlibImage *im, char *text)
{
	GdkPixmap *pixmap;
	GdkPixmap *im_pixmap;
	GdkBitmap *mask;
	GdkBitmap *im_mask;
	struct text_info *ti;
	GdkColor color;
	GdkGC *gc;
	int width, height;

	ti = layout_text (window, text);

	width = MAX (ti->width, im->rgb_width);
	height = im->rgb_height + SPACING + ti->height;

	/* pixmap */

	pixmap = gdk_pixmap_new (window->window, width, height, gdk_imlib_get_visual ()->depth);

	gc = gdk_gc_new (pixmap);

	gdk_color_white (gdk_imlib_get_colormap (), &color);
	gdk_gc_set_foreground (gc, &color);
	gdk_draw_rectangle (pixmap, gc, TRUE, 0, 0, width, height);

	im_pixmap = gdk_imlib_move_image (im);
	gdk_window_copy_area (pixmap, gc,
			      (width - im->rgb_width) / 2,
			      0,
			      im_pixmap,
			      0, 0,
			      im->rgb_width, im->rgb_height);
	gdk_imlib_free_pixmap (im_pixmap);

	/* mask */

	mask = gdk_pixmap_new (window->window, width, height, 1);

	gc = gdk_gc_new (mask);

	color.pixel = 0;
	gdk_gc_set_foreground (gc, &color);
	gdk_draw_rectangle (mask, gc, TRUE, 0, 0, width, height);

	im_mask = gdk_imlib_move_mask (im);
	if (im_mask) {
		gdk_window_copy_area (mask, gc,
				      (width - im->rgb_width) / 2,
				      0,
				      im_mask,
				      0, 0,
				      im->rgb_width, im->rgb_height);
		gdk_imlib_free_bitmap (im_mask);
	}
	
	color.pixel = 1;
	gdk_gc_set_foreground (gc, &color);
	paint_text (ti, mask, gc,
		    (width - ti->width) / 2,
		    im->rgb_height + SPACING);

	gdk_gc_destroy (gc);

	/* set contents */

	gtk_widget_set_usize (window, width, height);
	gdk_window_set_back_pixmap (window->window, pixmap, FALSE);
	gdk_window_shape_combine_mask (window->window, mask, 0, 0);

	gdk_pixmap_unref (pixmap);
	gdk_pixmap_unref (mask);

	text_info_free (ti);
}

GtkWidget *
create_transparent_text_window (char *file, char *text, int extra_events)
{
	GtkWidget *window;
	GdkImlibImage *im;
	static GdkCursor *cursor;

	if (!g_file_exists (file))
		return NULL;


	im = image_cache_load_image (file);
	if (!im)
		return NULL;

	gtk_widget_push_visual (gdk_imlib_get_visual ());
	gtk_widget_push_colormap (gdk_imlib_get_colormap ());
	
	window = gtk_window_new (GTK_WINDOW_POPUP);
	gtk_widget_set_events (window, gtk_widget_get_events (window) | extra_events);

	gtk_widget_pop_colormap ();
	gtk_widget_pop_visual ();

	gtk_widget_realize (window);
	
	gdk_imlib_render (im, im->rgb_width, im->rgb_height);

	set_window_text (window, im, text);

	if (!cursor)
		cursor = gdk_cursor_new (GDK_TOP_LEFT_ARROW); /* FIXME: this is never freed */

	gdk_window_set_cursor (window->window, cursor);

	return window;
}

GtkWidget *
make_transparent_window (char *file)
{
	GdkImlibImage *im;
	GtkWidget *window;
	XSetWindowAttributes xwa;
	
	if (!g_file_exists (file))
		return NULL;

	im = image_cache_load_image (file);
	if (!im)
		return NULL;

	gtk_widget_push_visual (gdk_imlib_get_visual ());
	gtk_widget_push_colormap (gdk_imlib_get_colormap ());

	window = gtk_window_new (GTK_WINDOW_POPUP);
	gtk_widget_pop_colormap ();
	gtk_widget_pop_visual ();

	gtk_widget_realize (window);

	xwa.save_under = True;
	XChangeWindowAttributes (GDK_WINDOW_XDISPLAY (window->window),
				 GDK_WINDOW_XWINDOW (window->window),
				 CWSaveUnder, &xwa);

	gtk_widget_set_usize (window, im->rgb_width, im->rgb_height);

	/* All of the following 3 lines should not be required, only
	 * gdk_imlib_apply_image, but is is buggy.
	 */
	gdk_imlib_render (im, im->rgb_width, im->rgb_height);
	gdk_window_set_back_pixmap (window->window, gdk_imlib_move_image (im), FALSE);
	gdk_window_shape_combine_mask (window->window, gdk_imlib_move_mask (im), 0, 0);
	
	return window;
}