/* BUGS:
   1. Scrolling uses parent image to draw 'unchanged' (while it is changed because of compositing) part on child pixmap
   2. Scrolling very fast by mouse wheel leads to some blocks of raster lines drawn misplaced
*/

#include <gtk/gtk.h>
#include <math.h>

GtkWidget* drawingArea;
GtkWidget* child=0;

gboolean on_expose(GtkWidget* widget, GdkEventExpose* event, gpointer data)
{
    if(GTK_IS_SCROLLED_WINDOW(widget))
    {
        GdkRegion *region;
        if(!child)
            child=gtk_bin_get_child(GTK_BIN(widget));

        // show how the whole child pixmap looks by rendering it on drawing area
        gtk_widget_queue_draw(drawingArea);
        gdk_window_process_updates(drawingArea->window,FALSE);

        cairo_t* cr=gdk_cairo_create(widget->window);
        // set up clipping
        region=gdk_region_rectangle(&child->allocation);
        gdk_region_intersect(region,event->region);
        gdk_cairo_region(cr,region);
        cairo_clip(cr);

        // draw background
        cairo_set_source_rgb(cr,1,0,0);
        cairo_paint(cr);
        // draw the child
        gdk_cairo_set_source_pixmap(cr,child->window,child->allocation.x,child->allocation.y);
        cairo_paint_with_alpha(cr,0.7);

        cairo_destroy(cr);
    }
    else // draw on drawing area
    {
        if(child)
        {
            cairo_t* cr=gdk_cairo_create(widget->window);
            gdk_cairo_set_source_pixmap(cr,child->window,0,0);
            cairo_paint(cr);
            cairo_destroy(cr);
        }
    }


    return FALSE;
}

static GtkTreeModel *
create_and_fill_model (void)
{
  GtkListStore *treestore;
  GtkTreeIter toplevel, child;

  treestore = gtk_list_store_new ( 1,
				  G_TYPE_STRING );

  /* Append a top level row and leave it empty */
  int i;
#define NUM_ROWS 100
  for(i=0;i<NUM_ROWS;i++)
  {
      char datastring[1024];
      sprintf(datastring,"Test data... row %d... Make it wider..... still wider..................",i+1);;
      gtk_list_store_append (treestore, &toplevel);
      gtk_list_store_set (treestore, &toplevel,
                  0, datastring, -1);
  }

  return GTK_TREE_MODEL (treestore);
}


static GtkWidget *
create_view_and_model (void)
{
  GtkTreeViewColumn *col;
  GtkCellRenderer *renderer;
  GtkWidget *view;
  GtkTreeModel *model;

  view = gtk_tree_view_new ();
  gtk_widget_set_size_request(view,200,200);

  col = gtk_tree_view_column_new ();

  gtk_tree_view_column_set_title (col, "Column header");

  /* pack tree view column into tree view */
  gtk_tree_view_append_column (GTK_TREE_VIEW (view), col);

  renderer = gtk_cell_renderer_text_new ();

  /* pack cell renderer into tree view column */
  gtk_tree_view_column_pack_start (col, renderer, TRUE);

  /* connect 'text' property of the cell renderer to
   *  model column that contains the first name */
  gtk_tree_view_column_add_attribute (col, renderer, "text", 0 );

  model = create_and_fill_model ();

  gtk_tree_view_set_model (GTK_TREE_VIEW (view), model);

  g_object_unref (model);	/* destroy model automatically with view */

  return view;
}


int
main (int argc, char **argv)
{
  GtkWidget *window;
  GtkWidget *treeview;
  GtkWidget* hbox;
  GtkWidget* scrolled;

  gtk_init (&argc, &argv);

  window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
  scrolled=gtk_scrolled_window_new(0,0);
  treeview = create_view_and_model ();
  hbox=gtk_hbox_new(TRUE,0);
  drawingArea=gtk_drawing_area_new();

  gtk_container_add (GTK_CONTAINER (scrolled), treeview);
  gtk_container_add(GTK_CONTAINER(window),hbox);
  gtk_box_pack_start(GTK_BOX(hbox),scrolled,TRUE,TRUE,0);
  gtk_box_pack_start(GTK_BOX(hbox),drawingArea,TRUE,TRUE,0);
  gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled),GTK_POLICY_AUTOMATIC,GTK_POLICY_AUTOMATIC);

  gtk_widget_realize(treeview);
  gdk_window_set_composited(treeview->window,TRUE);
  g_signal_connect_after(G_OBJECT(scrolled),"expose-event",G_CALLBACK(on_expose),NULL);
  g_signal_connect(G_OBJECT(window), "delete_event", gtk_main_quit, NULL);
  g_signal_connect(G_OBJECT(drawingArea),"expose-event",G_CALLBACK(on_expose),(gpointer)1);

  gtk_widget_show_all (window);

  gtk_main ();

  return 0;
}
