#include <gtk/gtk.h>

#define MIN_SIZE_X 100
#define MIN_SIZE_Y 100

static void
update_scrolled (GtkLayout *layout)
{
	guint sizex = MIN_SIZE_X;
	guint sizey = MIN_SIZE_Y;
	GList *list, *iter;
	list = gtk_container_get_children (GTK_CONTAINER (layout));
	for (iter = list; iter; iter = iter->next)
	{
		GtkWidget *a = GTK_WIDGET (iter->data);
		if (gtk_widget_get_visible (a))
		{
			GtkAllocation l;
			gtk_widget_get_allocation (a, &l);
			if (sizex < (l.x + l.width))
				sizex = l.x + l.width;
			if (sizey < (l.y + l.height))
				sizey = l.y + l.height;
		}
	}
	g_list_free (list);
	gtk_layout_set_size (layout, sizex, sizey);
}

GtkWidget *w = 0;
double x;
double y;
GtkAllocation l;

GtkWidget *label1;
GtkWidget *label2;
GtkWidget *label3;

static gboolean
layout_button_press_event (GtkWidget      *widget,
                           GdkEventButton *event,
                           gpointer        user_data)
{
	fprintf (stderr, "button_press_event: %04lf %04lf %d\n", event->x, event->y, event->button);
	if (event->button == 1)
	{
		GList *list, *iter;
		list = gtk_container_get_children (GTK_CONTAINER (widget));
		for (iter = list; iter; iter = iter->next)
		{
			GtkWidget *a = GTK_WIDGET (iter->data);
			fprintf (stderr, "child: %p\n", a);
			if (gtk_widget_get_visible (a))
			{
				fprintf (stderr, " is visible\n");
				gtk_widget_get_allocation (a, &l);
				fprintf (stderr, "x: %d, y: %d, w: %d, h: %d\n", l.x, l.y, l.width, l.height);
				if ( (event->x >= l.x) &&
				     (event->x < (l.x + l.width)) &&
				     (event->y >= l.y) &&
				     (event->y < (l.y + l.height)))
				{
					w = a;
					x = event->x;
					y = event->y;
					break;
				}
			}
		}
		g_list_free (list);
		return TRUE; /* swallow event */
	}
	return FALSE;
}

static gboolean
layout_button_release_event (GtkWidget      *widget,
                             GdkEventButton *event,
                             gpointer        user_data)
{
	fprintf (stderr, "button_release_event: %04lf %04lf %d\n", event->x, event->y, event->button);
	if (event->button == 1)
	{
		w = 0;
		return TRUE; /* swallow event */
	}
	return FALSE;
}

static gboolean
layout_motion_notify_event (GtkWidget      *widget,
                            GdkEventMotion *event,
                            gpointer        user_data)
{
	fprintf (stderr, "motion_notify_event: %04lf %04lf\n", event->x, event->y);
	if (w)
	{
		gint newx = (gint)((event->x - x)) + l.x;
		gint newy = (gint)(event->y - y) + l.y;
		if (newx < 0)
			newx = 0;
		if (newy < 0)
			newy = 0;
		gtk_layout_move (GTK_LAYOUT (widget), w, newx, newy);
		gdk_window_invalidate_rect (gtk_layout_get_bin_window (GTK_LAYOUT (widget)), NULL, FALSE);

		return TRUE; /* swallow event */
	}
	return FALSE;
}

static gboolean
layout_expose_event (GtkWidget      *widget,
                     GdkEventExpose *event,
                     gpointer        user_data)
{
	GdkWindow *window;
	GdkGC *gc;
	GdkColor col;
	GdkPoint p[4];
	GtkAllocation a;

	fprintf (stderr, "expose_event\n");

	gtk_widget_get_allocation (label1, &a);
	p[0].x = p[3].x = a.x + a.width / 2;
	p[0].y = p[3].y = a.y + a.height / 2;
	gtk_widget_get_allocation (label2, &a);
	p[1].x = a.x + a.width / 2;
	p[1].y = a.y + a.height / 2;
	gtk_widget_get_allocation (label3, &a);
	p[2].x = a.x + a.width / 2;
	p[2].y = a.y + a.height / 2;

	window = gtk_layout_get_bin_window (GTK_LAYOUT (widget));
	gc = gdk_gc_new (window);

	col.pixel = 0;
	col.red = 0xffff;
	col.green = 0x8000;
	col.blue = 0x8000;
	gdk_gc_set_rgb_fg_color (gc, &col);

	gdk_gc_set_clip_region (gc, event->region);

	gdk_draw_lines (window,
	                gc,
	                p, 4);

	gdk_gc_unref (gc);

	update_scrolled (GTK_LAYOUT (widget));

	return FALSE;
}

static gboolean
window_delete_event (GtkWidget *widget,
                     GdkEvent  *event,
                     gpointer   user_data)
{
	fprintf (stderr, "delete-event\n");
	gtk_main_quit ();
	return FALSE;
}

int main(int argc, char *argv[])
{
	GtkWidget *window;
	GtkWidget *layout;
	GtkWidget *scroll;

	GtkWidget *button1;

	gtk_init (&argc, &argv);

	window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
	scroll = gtk_scrolled_window_new (NULL, NULL);
	layout = gtk_layout_new (NULL, NULL);
	gtk_container_add (GTK_CONTAINER (scroll), layout);
	gtk_container_add (GTK_CONTAINER (window), scroll);

	label1 = gtk_label_new ("label 1");
	label2 = gtk_label_new ("label 2");
	label3 = gtk_label_new ("label 3");
	button1 = gtk_button_new_with_label ("button 1");

	gtk_layout_put (GTK_LAYOUT (layout), label1, 10, 50);
	gtk_layout_put (GTK_LAYOUT (layout), label2, 50, 50);
	gtk_layout_put (GTK_LAYOUT (layout), label3, 50, 100);
	gtk_layout_put (GTK_LAYOUT (layout), button1, 100, 100);

	gtk_widget_show_all (window);

	update_scrolled (GTK_LAYOUT (layout));

	gtk_widget_add_events (layout, GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK | GDK_BUTTON_MOTION_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK);

	g_signal_connect (layout, "button-press-event", G_CALLBACK (layout_button_press_event), NULL);
	g_signal_connect (layout, "button-release-event", G_CALLBACK (layout_button_release_event), NULL);
	g_signal_connect (layout, "motion-notify-event", G_CALLBACK (layout_motion_notify_event), NULL);
	g_signal_connect (layout, "expose-event", G_CALLBACK (layout_expose_event), NULL);
	g_signal_connect (window, "delete-event", G_CALLBACK (window_delete_event), NULL);

	gtk_main ();

	return 0;
}

