/* -*- Mode: C; c-file-style: "gnu"; tab-width: 8 -*- */
#include <gtk/gtk.h>

gchar *tabs1 [] = {
  "a",
  "b",
  "c",
  "d",
  NULL
};

gchar *tabs2 [] = {
  "1",
  "2",
  "3",
  "4",
  "5",
  NULL
};

gchar *tabs3 [] = {
  "foo",
  "bar",
  NULL
};

gchar *tabs4 [] = {
  "beer",
  "water",
  "lemonade",
  "coffee",
  "tea",
  NULL
};

typedef struct {
  int x;
  int y;
  gboolean found;
  gboolean first;
  GtkWidget *res_widget;
} FindWidgetData;

static void
find_widget (GtkWidget *widget, FindWidgetData *data)
{
  GtkAllocation new_allocation;
  gint x_offset = 0;
  gint y_offset = 0;

  new_allocation = widget->allocation;

  if (data->found || !GTK_WIDGET_MAPPED (widget))
    return;

  /* Note that in the following code, we only count the
   * position as being inside a WINDOW widget if it is inside
   * widget->window; points that are outside of widget->window
   * but within the allocation are not counted. This is consistent
   * with the way we highlight drag targets.
   */
  if (!GTK_WIDGET_NO_WINDOW (widget))
    {
      new_allocation.x = 0;
      new_allocation.y = 0;
    }
  
  if (widget->parent && !data->first)
    {
      GdkWindow *window = widget->window;
      while (window != widget->parent->window)
	{
	  gint tx, ty, twidth, theight;
	  gdk_drawable_get_size (window, &twidth, &theight);

	  if (new_allocation.x < 0)
	    {
	      new_allocation.width += new_allocation.x;
	      new_allocation.x = 0;
	    }
	  if (new_allocation.y < 0)
	    {
	      new_allocation.height += new_allocation.y;
	      new_allocation.y = 0;
	    }
	  if (new_allocation.x + new_allocation.width > twidth)
	    new_allocation.width = twidth - new_allocation.x;
	  if (new_allocation.y + new_allocation.height > theight)
	    new_allocation.height = theight - new_allocation.y;

	  gdk_window_get_position (window, &tx, &ty);
	  new_allocation.x += tx;
	  x_offset += tx;
	  new_allocation.y += ty;
	  y_offset += ty;
	  
	  window = gdk_window_get_parent (window);
	}
    }

  if ((data->x >= new_allocation.x) && (data->y >= new_allocation.y) &&
      (data->x < new_allocation.x + new_allocation.width) && 
      (data->y < new_allocation.y + new_allocation.height))
    {
      /* First, check if the drag is in a valid drop site in
       * one of our children 
       */
      if (GTK_IS_CONTAINER (widget))
	{
	  FindWidgetData new_data = *data;
	  
	  new_data.x -= x_offset;
	  new_data.y -= y_offset;
	  new_data.found = FALSE;
	  new_data.first = FALSE;
	  
	  gtk_container_forall (GTK_CONTAINER (widget),
				(GtkCallback)find_widget,
				&new_data);
	  
	  data->found = new_data.found;
	  if (data->found)
	    data->res_widget = new_data.res_widget;
	}

      /* If not, and this widget is registered as a drop site, check to
       * emit "drag_motion" to check if we are actually in
       * a drop site.
       */
      if (!data->found)
	{
	  data->found = TRUE;
	  data->res_widget = widget;
	}
    }
}

static GtkWidget *
find_widget_at_pointer (GdkDisplay *display, 
			GType       type)
{
  GtkWidget *widget = NULL;
  GdkWindow *pointer_window;
  gint x, y;
  FindWidgetData data;
 
 pointer_window = gdk_display_get_window_at_pointer (display, NULL, NULL);
 
 if (pointer_window)
   gdk_window_get_user_data (pointer_window, (gpointer*) &widget);

 if (widget)
   {
     gdk_window_get_pointer (widget->window,
			     &x, &y, NULL);
     
     data.x = x;
     data.y = y;
     data.found = FALSE;
     data.first = TRUE;

     find_widget (widget, &data);
     if (data.found)
       widget = data.res_widget;
     else 
       widget = NULL;
   }
 
 while (widget)
   {
     if (g_type_check_instance_is_a (widget, type))
       break;

     widget = gtk_widget_get_parent (widget);
   }

 return widget;
}


static void
on_tab_detached (GtkWidget *widget, GtkWidget *child, gpointer user_data)
{
  GdkDisplay *display;
  GtkWidget *label, *dest_widget;
  gboolean tab_expand;
  gboolean tab_fill;
  gboolean reorderable;
  gboolean detachable;

  g_print ("tab detached\n");


  display = gdk_display_get_default ();

  dest_widget = find_widget_at_pointer (display, GTK_TYPE_NOTEBOOK);

  if (!dest_widget)
    {
      g_print ("no on notebook\n");
      return;
    }

  label = gtk_notebook_get_tab_label (GTK_NOTEBOOK (widget), child);

  g_object_ref (child);
  g_object_ref (label);
  
  gtk_container_child_get (GTK_CONTAINER (widget), child,
			   "tab-expand", &tab_expand,
			   "tab-fill", &tab_fill,
			   "reorderable", &reorderable,
			   "detachable", &detachable,
			   NULL);
  
  gtk_container_remove (GTK_CONTAINER (widget), child);

  gtk_notebook_append_page (GTK_NOTEBOOK (dest_widget), child, label);

  gtk_container_child_set (GTK_CONTAINER (dest_widget), child,
			   "tab-expand", tab_expand,
			   "tab-fill", tab_fill,
			   "reorderable", reorderable,
			   "detachable", detachable,
			   NULL);  

  g_object_unref (child);
  g_object_unref (label);
}

static GtkWidget*
create_notebook (gchar **labels)
{
  GtkWidget *notebook, *title, *label;

  notebook = gtk_notebook_new ();

  gtk_notebook_set_scrollable (GTK_NOTEBOOK (notebook), TRUE);
  gtk_container_set_border_width (GTK_CONTAINER (notebook), 6);

  while (*labels)
    {
      label = gtk_label_new (*labels);
      title = gtk_label_new (*labels);

      gtk_notebook_append_page (GTK_NOTEBOOK (notebook), label, title);
      gtk_notebook_set_tab_reorderable (GTK_NOTEBOOK (notebook), label, TRUE);
      gtk_notebook_set_tab_detachable (GTK_NOTEBOOK (notebook), label, TRUE);

      labels++;
    }

  g_signal_connect (G_OBJECT (notebook), "tab-detached",
		    G_CALLBACK (on_tab_detached), NULL);

  return notebook;
}

gint
main (gint argc, gchar *argv[])
{
  GtkWidget *window, *table;

  gtk_init (&argc, &argv);

  window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
  table = gtk_table_new (2, 2, TRUE);

  gtk_table_attach_defaults (GTK_TABLE (table), create_notebook (tabs1), 0, 1, 0, 1);
  gtk_table_attach_defaults (GTK_TABLE (table), create_notebook (tabs2), 0, 1, 1, 2);
  gtk_table_attach_defaults (GTK_TABLE (table), create_notebook (tabs3), 1, 2, 0, 1);
  gtk_table_attach_defaults (GTK_TABLE (table), create_notebook (tabs4), 1, 2, 1, 2);

  gtk_container_add (GTK_CONTAINER (window), table);
  gtk_window_set_default_size (GTK_WINDOW (window), 400, 400);
  gtk_widget_show_all (window);

  gtk_main ();

  return 0;
}
