Revision 23667 (by benny, 2006/11/04 16:16:51) 2006-11-04 Benedikt Meurer <benny@xfce.org>

* configure.in.in: Post-release version bump.
* src/window.c: Add root warning. bug #2245.
* po/mousepad.pot, po/*.po: Merge new strings.
* po/de.po: Updated german translations.


/*
 *  linenum.c
 *  This file is part of Leafpad
 *
 *  Copyright (C) 2004 Tarot Osuji
 *
 *  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 of the License, 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/gtk.h>

#define	DV(x)

static gint min_number_window_width;
static const gint margin = 5;

static gint calculate_min_number_window_width(GtkWidget *widget)
{
	PangoLayout *layout;
	gchar *str;
	gint width, col = 4;

	str = g_strnfill(col, 0x20);
	layout = gtk_widget_create_pango_layout(widget, str);
	g_free (str);

	pango_layout_get_pixel_size(layout, &width, NULL);
	g_object_unref(G_OBJECT(layout));

	return width;
}

/* taken from gedit and gtksourceview */
/* originated from gtk+/tests/testtext.c */

static void
get_lines (GtkTextView  *text_view,
           gint          y1,
           gint          y2,
           GArray       *buffer_coords,
           GArray       *numbers,
           gint         *countp)
{
	GtkTextIter iter;
	gint count;
	gint size;
		gint last_line_num;
	
	g_array_set_size (buffer_coords, 0);
	g_array_set_size (numbers, 0);
	
	/* Get iter at first y */
	gtk_text_view_get_line_at_y (text_view, &iter, y1, NULL);
	
	/* For each iter, get its location and add it to the arrays.
	 * Stop when we pass y2
	 */
	count = 0;
	size = 0;
	
	while (!gtk_text_iter_is_end (&iter))
	{
		gint y, height;
		
		gtk_text_view_get_line_yrange (text_view, &iter, &y, &height);
		
		g_array_append_val (buffer_coords, y);
		last_line_num = gtk_text_iter_get_line (&iter);
		g_array_append_val (numbers, last_line_num);
		
		++count;
		
		if ((y + height) >= y2)
		break;
		
		gtk_text_iter_forward_line (&iter);
	}
	
	if (gtk_text_iter_is_end (&iter))
	{
		gint y, height;
		gint line_num;
		
		gtk_text_view_get_line_yrange (text_view, &iter, &y, &height);
		
		line_num = gtk_text_iter_get_line (&iter);
		
		if (line_num != last_line_num) {
			g_array_append_val (buffer_coords, y);
			g_array_append_val (numbers, line_num);
			++count;
		}
	}
	
	*countp = count;
}

static gint
line_numbers_expose (GtkWidget      *widget,
                     GdkEventExpose *event)
{
	GtkTextView *text_view;
	GdkWindow *win;
/*	GtkStyle *style; */
	PangoLayout *layout;
	PangoAttrList *alist;
	PangoAttribute *attr;
	GArray *numbers;
	GArray *pixels;
	gint y1, y2;
	gint count;
	gint layout_width;
	gint justify_width = 0;
	gint i;
/*	gchar *str; */
	gchar str [8];  /* we don't expect more than ten million lines */
	
	text_view = GTK_TEXT_VIEW (widget);
	
	/* See if this expose is on the line numbers window */
/*	left_win = gtk_text_view_get_window (text_view,
	                                     GTK_TEXT_WINDOW_LEFT);
	right_win = gtk_text_view_get_window (text_view,
	                                      GTK_TEXT_WINDOW_RIGHT);
	
	if (event->window == left_win)
	{
		type = GTK_TEXT_WINDOW_LEFT;
		target = event->window;
	}
	else if (event->window == right_win)
	{
		type = GTK_TEXT_WINDOW_RIGHT;
		target = right_win;
	}
	else
		return FALSE;
*/	
	win = gtk_text_view_get_window (text_view,
	                                GTK_TEXT_WINDOW_LEFT);
	if (event->window != win)
		return FALSE;
	
/*	style = gtk_style_copy (widget->style);
 *	style = gtk_style_copy (gtk_widget_get_default_style());
 */	
	y1 = event->area.y;
	y2 = y1 + event->area.height;
	
	gtk_text_view_window_to_buffer_coords (text_view,
	                                       GTK_TEXT_WINDOW_LEFT,
	                                       0,
	                                       y1,
	                                       NULL,
	                                       &y1);
	
	gtk_text_view_window_to_buffer_coords (text_view,
	                                       GTK_TEXT_WINDOW_LEFT,
	                                       0,
	                                       y2,
	                                       NULL,
	                                       &y2);
	
	numbers = g_array_new (FALSE, FALSE, sizeof (gint));
	pixels = g_array_new (FALSE, FALSE, sizeof (gint));
	
	get_lines (text_view,
	           y1,
	           y2,
	           pixels,
	           numbers,
	           &count);
	
	/* a zero-lined document should display a "1"; we don't need to worry about
	scrolling effects of the text widget in this special case */
	
	if (count == 0)
	{
		gint y = 0;
		gint n = 0;
		count = 1;
		g_array_append_val (pixels, y);
		g_array_append_val (numbers, n);
	}
	
DV({g_print("Painting line numbers %d - %d\n",
			g_array_index(numbers, gint, 0),
			g_array_index(numbers, gint, count - 1));	});
	
	layout = gtk_widget_create_pango_layout (widget, "");
	
/*	str = g_strdup_printf ("%d", gtk_text_buffer_get_line_count(text_view->buffer)); */
	g_snprintf (str, sizeof (str),
			"%d", MAX (99, gtk_text_buffer_get_line_count(text_view->buffer)));
	pango_layout_set_text (layout, str, -1);
/*	g_free (str); */
	
	pango_layout_get_pixel_size (layout, &layout_width, NULL);
	
	min_number_window_width = calculate_min_number_window_width(widget);
	if (layout_width > min_number_window_width)
		gtk_text_view_set_border_window_size (text_view,
											  GTK_TEXT_WINDOW_LEFT,
											  layout_width + margin);
	else {
/*		if ((gtk_text_view_get_border_window_size (text_view, GTK_TEXT_WINDOW_LEFT) - 5) > layout_width) { */
			gtk_text_view_set_border_window_size (text_view,
												  GTK_TEXT_WINDOW_LEFT,
												  min_number_window_width + margin);
/*		} */
		justify_width = min_number_window_width - layout_width;
	}
	
	pango_layout_set_width (layout, layout_width);
	pango_layout_set_alignment (layout, PANGO_ALIGN_RIGHT);
	
	alist = pango_attr_list_new();
	attr = pango_attr_foreground_new(
		widget->style->text_aa->red,
		widget->style->text_aa->green,
		widget->style->text_aa->blue);
	attr->start_index = 0;
	attr->end_index = G_MAXUINT;
	pango_attr_list_insert(alist, attr);
	pango_layout_set_attributes(layout, alist);
	
	/* Draw fully internationalized numbers! */
	
	i = 0;
	while (i < count)
	{
		gint pos;
		
		gtk_text_view_buffer_to_window_coords (text_view,
		                                       GTK_TEXT_WINDOW_LEFT,
		                                       0,
		                                       g_array_index (pixels, gint, i),
		                                       NULL,
		                                       &pos);
		
/*		str = g_strdup_printf ("%d", g_array_index (numbers, gint, i) + 1); */
		g_snprintf (str, sizeof (str),
				"%d", g_array_index (numbers, gint, i) + 1);
		
		pango_layout_set_text (layout, str, -1);
		
		gtk_paint_layout (widget->style,
		                  win,
		                  GTK_WIDGET_STATE (widget),
		                  FALSE,
		                  NULL,
		                  widget,
		                  NULL,
		                  layout_width + justify_width + 1, pos,
		                  layout);
/*		g_free (str); */
		
		++i;
	}
	
	g_array_free (pixels, TRUE);
	g_array_free (numbers, TRUE);
	
	g_object_unref (G_OBJECT (layout));
/*	g_object_ref (G_OBJECT (style)); */
	
	/* don't stop emission, need to draw children */
	return FALSE;
}

void show_line_numbers(GtkWidget *text_view, gboolean visible)
{
	if (visible) {
		min_number_window_width = calculate_min_number_window_width(text_view);
		gtk_text_view_set_border_window_size(
			GTK_TEXT_VIEW(text_view),
			GTK_TEXT_WINDOW_LEFT,
			min_number_window_width + margin);
		g_signal_connect(
			G_OBJECT(text_view),
			"expose_event",
			G_CALLBACK(line_numbers_expose),
			NULL);
	} else {
		gtk_text_view_set_border_window_size(
			GTK_TEXT_VIEW(text_view),
			GTK_TEXT_WINDOW_LEFT,
			0);
		g_signal_handlers_disconnect_by_func(
			G_OBJECT(text_view),
			G_CALLBACK(line_numbers_expose),
			NULL);
	}
}