// Copyright (C) 2001 Jean-Marc Valin

#include "GUINetwork.h"
#include "GUIDocument.h"
#include "GUINode.h"
#include "GUINote.h"
#include "GUITerminal.h"
#include <libxml/tree.h>
#include "GUILink.h"
#include "GUINetPopup.h"
#include "Node.h"
#include "GUINetTerminal.h"
#include "canvas-background.h"
#include "misc.h"
#include "GUINodeTooltip.h"
#include <sstream>
#include "GUINote.h"

using namespace std;

namespace FD {



void canvas_drag_data_received  (GtkWidget *widget,
			      GdkDragContext     *context,
			      gint                x,
			      gint                y,
			      GtkSelectionData   *data,
			      guint               info,
			      guint               time,
			      GUINetwork          *net)
{

  //cerr<<"Got drag_data for widget "<<widget<<endl;
  //cerr<<"Got drag_data for GUINetwork "<<net<<endl;
  //g_print("Canvas Got: %s\n",data->data);

  if (net) {

    string nodeType((const char*)data->data);

    int offset_x;
    int offset_y;

    gnome_canvas_get_scroll_offsets(net->canvas,&offset_x,&offset_y);

    double world_x;
    double world_y;

    //gnome_canvas_w2c(net->canvas,world_x,world_y,&cx,&cy);
    
    gnome_canvas_c2w (net->canvas,x+offset_x,y+offset_y,&world_x,&world_y);
    net->addNode(nodeType,world_x,world_y);

  }
  
}


void check_resize (GtkContainer *container, GUINetwork *net)
{
  cerr<<"check resize"<<endl;
}


static gint background_handler (GnomeCanvasItem *item, GdkEvent *event, GUINetwork      *net)
{  
  return net->buttonEvent(event);

}

GUINetwork::GUINetwork(UIDocument *_doc, string _name, Type _type)
   : UINetwork(_doc, _name, _type)
   , zoom(1)
   , tooltip(NULL)
   , networkProperties(NULL)
{
   create();
}

GUINetwork::GUINetwork(UIDocument *_doc, xmlNodePtr net)
   : UINetwork(_doc, net, false)
   , zoom(1)
   , tooltip(NULL)
   , networkProperties(NULL)
{
   //cerr << "GUINetwork::GUINetwork\n";
   name = string((char *)xmlGetProp(net, (xmlChar *)"name"));
   char *netType = (char *)xmlGetProp(net, (xmlChar *)"type");
   
   if (!netType)
   {
      type=subnet;
      //cerr << "netType == NILL\n";
   }   
   else {
      //cerr << "netType = " << netType << endl;
      if (netType == string("subnet"))
	 type=subnet;
      else if (netType == string("iterator"))
	 type=iterator;
      else if (netType == string("threaded"))
	 type=threaded;
   }
   //cerr << "type = " << type << endl;

   //cerr << "creating network in GUINetwork::GUINetwork\n";
   create();
   //cerr << "loading...\n";
   load(net);
   //cerr << "loaded\n";
}

GUINetwork::~GUINetwork() 
{
   //It's important that destroyed be set here because is has an effect 
   //on methods that are called indirectly from the destructor.

  //cerr<<"GUINetwork destroyed :"<<destroyed<<" name : "<<getName()<<endl;

  if (!destroyed) {

   
    //Links are deleted through the nodes destructor
    for (int i=0;i<nodes.size();i++) {
      string my_name = nodes[i]->getName();
      //cerr<<"GUINetwork::~GUINetwork deleting node "<<nodes[i]->getName()<<endl;
      delete nodes[i];
      
   }
    
    delete popup;
    gtk_object_destroy(GTK_OBJECT(group));
    gtk_widget_destroy(GTK_WIDGET(scrolledwindow1));

    if (networkProperties) {
      gtk_widget_destroy(GTK_WIDGET(networkProperties));
      networkProperties = NULL;
    }

    destroyed=true;
  }
    
}

void GUINetwork::create()
{
   //cerr << "GUINetwork::create()\n";
  

   //last page will be used.
   //cerr << "GUINetwork::create() name : "<<name<<endl;
   //cerr << "GUINetwork::create() with notebook : "<<document_notebook<<endl;

   //gtk_widget_show (notebook1);

   scrolledwindow1 = gtk_scrolled_window_new (NULL, NULL);

   gtk_object_set_data(GTK_OBJECT(scrolledwindow1), "net", this);

   gtk_widget_ref (scrolledwindow1);

   //gtk_object_set_data_full (GTK_OBJECT (notebook1), "scrolledwindow1", scrolledwindow1,
   //                          (GtkDestroyNotify) gtk_widget_unref);
   gtk_widget_show (scrolledwindow1);
   //gtk_container_add (GTK_CONTAINER (notebook1), scrolledwindow1);

   gdk_rgb_init ();
   gtk_widget_push_visual (gdk_rgb_get_visual ());
   gtk_widget_push_colormap (gdk_rgb_get_cmap ());
   GtkWidget *canvas1 = gnome_canvas_new ();
   gtk_object_set_data_full (GTK_OBJECT (scrolledwindow1), "canvas1", canvas1,
                             (GtkDestroyNotify) gtk_widget_unref);

   gtk_widget_pop_colormap ();
   gtk_widget_pop_visual ();

   

   //gtk_object_set_data_full (GTK_OBJECT (scrolledwindow1), "canvas1", canvas1,
   //                          (GtkDestroyNotify) gtk_widget_unref);
   gtk_widget_show (canvas1);
   gtk_container_add (GTK_CONTAINER (scrolledwindow1), canvas1);
   gnome_canvas_set_scroll_region (GNOME_CANVAS (canvas1), -400, -400, 400, 400);



   /* DRAG & DROP TEST */
   //DL FEB 3 2006
   static GtkTargetEntry target_table[] = {
     { "text/plain", 0, 0 }
   };
    
   
   gtk_drag_dest_set (canvas1,
		      GTK_DEST_DEFAULT_ALL,
		      target_table, 1,
		      GDK_ACTION_COPY);


   gtk_signal_connect (GTK_OBJECT (canvas1), "drag_data_received",
		       GTK_SIGNAL_FUNC (canvas_drag_data_received),
		       this);


   
   gtk_signal_connect(GTK_OBJECT(canvas1), "check-resize",
		      (GtkSignalFunc) check_resize,
		      this);


   /* DRAG & DROP TEST END */


   
   //add this network to the document
   dynamic_cast<GUIDocument*>(doc)->add_notebook_network(this,scrolledwindow1);


   canvas=GNOME_CANVAS(canvas1);


   GnomeCanvasItem *background = gnome_canvas_item_new(gnome_canvas_root(canvas),
						       gnome_canvas_background_get_type(),
						       NULL);

   gtk_signal_connect(GTK_OBJECT(background), "event",
                      (GtkSignalFunc) background_handler,
                      this);



   //group = gnome_canvas_root(canvas);
   group = GNOME_CANVAS_GROUP (gnome_canvas_item_new (gnome_canvas_root(canvas),
                                                      gnome_canvas_group_get_type(),
                                                      "x", 0.0,
                                                      "y", 0.0,
                                                      NULL));
   popup = new GUINetPopup(doc,this);

   /* gtk_signal_connect (GTK_OBJECT (canvas), "button_press_event",
                       GTK_SIGNAL_FUNC (net_canvas_event),
                       this);
   
   */

   
}


void GUINetwork::updateScroll ()
{
   double x1,y1,x2,y2;
   double mx1=DBL_MAX,my1=DBL_MAX,mx2=-DBL_MAX,my2=-DBL_MAX;
   //gint ix,iy;
   gnome_canvas_get_scroll_region(canvas,&x1,&y1,&x2,&y2);
   if (!nodes.size())
   {
      gnome_canvas_set_scroll_region(canvas, x1,y1,x2,y2);
      gnome_canvas_item_move(GNOME_CANVAS_ITEM(group), 0, 0);
      return;
   }
   for (int i=0;i<nodes.size();i++)
   {
      double xx,yy;
      nodes[i]->getPos(xx,yy);
      mx1=min(mx1,xx);
      my1=min(my1,yy);
      mx2=max(mx2,xx);
      my2=max(my2,yy);
   }
   mx1-=400;
   my1-=400;
   mx2+=400;
   my2+=400;

   if ((abs(mx1-x1)>100) || (abs(my1-y1)>100) || (abs(mx2-x2)>100) || (abs(my2-y2)>100))
      gnome_canvas_set_scroll_region(canvas, mx1,my1,mx2,my2);
   else 
      gnome_canvas_set_scroll_region(canvas, x1,y1,x2,y2);
   //gnome_canvas_get_scroll_offsets(canvas,&ix,&iy);
   //gnome_canvas_scroll_to(canvas,ix,iy);

   gnome_canvas_item_move(GNOME_CANVAS_ITEM(group), 0, 0);

}

UINode * GUINetwork::addNode (string type, double xx, double yy)
{
   double x,y;
   double x1,y1,x2,y2;
   gint ix,iy;
   //cerr << "my name is " ;
   //cerr << name << endl;
   //why?
   //gnome_canvas_window_to_world(canvas, xx,yy,&x,&y);

   //x=xx;
   //y=yy;
   //why?
   //gnome_canvas_item_w2i(GNOME_CANVAS_ITEM(group)->parent, &x, &y);

   char newName[256];
   int id=0;
   while (1) {
      id++;
      bool unique = true;
      sprintf (newName,"node_%s_%d",type.c_str(),id);
      for (int i=0;i<nodes.size();i++)
      {
         if (nodes[i]->getName() == newName) 
            unique = false;
      }
      if (unique)
         break;
   }
   UINode *my_newNode = new GUINode (this, newName, type, xx, yy);
   nodes.insert(nodes.end(), my_newNode);
   updateScroll();

   doc->setModified();
   return my_newNode;
}


gboolean GUINetwork::buttonEvent(GdkEvent *event) {
  
  static GnomeCanvasItem *item = NULL;
  static double x,y;
  double item_x, item_y;
  
  item_x = event->button.x;
  item_y = event->button.y;
  
 


   switch (event->type) {

   
   case GDK_BUTTON_PRESS:

     //keeping last click
     x_last_click = item_x;
     y_last_click = item_y;
     
     switch(event->button.button) {
       
     case 1:
    
       if (item) {
	 gtk_object_destroy(GTK_OBJECT(item));
       }

       item = gnome_canvas_item_new (group,
				     gnome_canvas_rect_get_type(),
				     "x1",item_x,
				     "y1",item_y,
				     "x2",item_x,
				     "y2",item_y,
				     "outline_color","blue",NULL);

       selectedNodes.resize(0);

       x = item_x;
       y = item_y;
       
       break;
       
     case 3:

       //update popup
       delete popup;
       popup = new GUINetPopup(doc,this);

       dynamic_cast<GUIDocument*>(doc)->updateSubnet();

       popup->popup(event);

       return TRUE;
       break;
       
     default:
       break;
     }
     break;

   case GDK_MOTION_NOTIFY:
     
     //resizing rectangle
     if (event->motion.state & GDK_BUTTON1_MASK) {
       if (item_x > x) {
	 gnome_canvas_item_set (item, "x2",item_x,NULL);
       }
       else {
	 gnome_canvas_item_set (item, "x1",item_x,"x2",x,NULL);  
       }
       if (item_y > y) {
	 gnome_canvas_item_set (item, "y2",item_y,NULL);
       }
       else {
	 gnome_canvas_item_set (item, "y1",item_y,"y2",y,NULL);
       }

       
       selectedNodes.resize(0);

       double ibx1,iby1,ibx2,iby2;
       gnome_canvas_item_get_bounds (item,
				     &ibx1,
				     &iby1,
				     &ibx2,
				     &iby2);

       for (int i = 0; i < nodes.size(); i++) {

	 GUINode *nodePtr = dynamic_cast<GUINode*>(nodes[i]);
	 if (nodePtr) {

	   double nx1,ny1,nx2,ny2;

	   nodePtr->getBounds(nx1,ny1,nx2,ny2);

	   if (nx1 >= ibx1 && 
	       nx2 <= ibx2 &&
	       ny1 >= iby1 &&
	       ny2 <= iby2) {

	     selectedNodes.push_back(nodePtr);
	    
	     //node inside rectangle
	     nodePtr->select();

	   }
	   else {
	     nodePtr->unselect();
	   }
	 }
       }
     }
     break;

   case GDK_BUTTON_RELEASE:
     //destroying the rectangle

     if (item) {

       for(int i = 0; i < nodes.size(); i++) {

	 GUINode *nodePtr = dynamic_cast<GUINode*>(nodes[i]);
	 
	 if (isNodeSelected(nodePtr)) {
	   nodePtr->select();
	 }
	 else {
	   nodePtr->unselect();
	 }
       }

       gtk_object_destroy(GTK_OBJECT(item));
       item = NULL;
     }

     break;

   case GDK_LEAVE_NOTIFY:      
     break;

   }//switch event
   /*
   switch (event->button) {
    case 1:
       //printf ("button 1\n");
    break;
    case 2:
       //printf ("button 2\n");
       //UIDocument::currentDocument->saveXML("tata.xml");
    break;
    case 3:
       //printf ("button 3\n");
       popup->popup(event);
       //nodeMenu->popup(event);
       //addNode("PS", 100.0,100.0);
       //UIDocument::currentDocument->popupNodeMenu(event);
    break;
    }*/
  return FALSE;
}

void GUINetwork::newNetNotify(const string &cat, const string &type) 
{
   if (type != name) 
      popup->addType(cat,type);
}


UITerminal *GUINetwork::isNearInputTerminal (double &x, double &y)
{
   for (int i=0;i<nodes.size();i++)
   {
      GUINode *theNode = dynamic_cast<GUINode *> (nodes[i]);
      //UINode *node=nodes[i];
      for (int j=0;j<theNode->inputs.size();j++)
         if (dynamic_cast<GUITerminal *> (theNode->inputs[j])->dist(x,y) < 5)
         {
            dynamic_cast<GUITerminal *> (theNode->inputs[j])->getPos(x,y);
            return theNode->inputs[j];
         }
   }
   return NULL;
}

UITerminal *GUINetwork::isNearOutputTerminal (double &x, double &y)
{
   for (int i=0;i<nodes.size();i++)
   {
      GUINode *theNode = dynamic_cast<GUINode *> (nodes[i]);
      //UINode *node=nodes[i];
      for (int j=0;j<theNode->outputs.size();j++)
         if (dynamic_cast<GUITerminal *> (theNode->outputs[j])->dist(x,y) < 5)
         {
            dynamic_cast<GUITerminal *> (theNode->outputs[j])->getPos(x,y);
            return theNode->outputs[j];
         }
   }
   return NULL;
}


UINode *GUINetwork::newNode(UINetwork* _net, xmlNodePtr def) {
  return new GUINode(_net, def);
}


UINode *GUINetwork::newNode(UINetwork* _net, string _name, string _type, double _x, double _y, bool doInit) {
  return new GUINode(_net, _name, _type, _x, _y);
}


/*UITerminal *GUINetwork::newTerminal (string _name, UINode *_node, bool _isInput, double _x, double _y)
{
   return new GUITerminal (_name, _node, _isInput, _x, _y);
}*/

UILink *GUINetwork::newLink (UITerminal *_from, UITerminal *_to, const char *str)
{
   return new GUILink (_from, _to, str);
}

UINetTerminal *GUINetwork::newNetTerminal (UITerminal *_terminal, UINetTerminal::NetTermType _type, const string &_name,
					   const string &_objType, const string &_description )
{
  return new GUINetTerminal (_terminal, _type, _name, _objType, _description);
}

void GUINetwork::moveSelectedNodes(double dx, double dy) {

  for (list<GUINode*>::iterator iter = selectedNodes.begin();
       iter != selectedNodes.end(); iter++) {
    (*iter)->selectedMove(dx,dy);
  }


}

bool GUINetwork::isNodeSelected(GUINode *node) {

  for (list<GUINode*>::iterator iter = selectedNodes.begin();
       iter != selectedNodes.end(); iter++) {
    if ((*iter) == node) return true;
  }


  return false;
}

void GUINetwork::clearSelectedNodes() {

  while (!selectedNodes.empty()) {
    GUINode *my_node = selectedNodes.front();
    selectedNodes.pop_front();
    delete my_node;
  }

}

void GUINetwork::emptySelectedNodes() { 

  while (!selectedNodes.empty()) {
    GUINode *my_node = selectedNodes.front();
    my_node->unselect();
    selectedNodes.pop_front();
  }
}

void GUINetwork::addSelectedNode(GUINode *node) {

  bool found = false;

  //prevent adding selectedNode twice
  for (list<GUINode*>::iterator iter = selectedNodes.begin(); 
       iter != selectedNodes.end(); iter++) {
    if ((*iter) == node) found = true;
  }

  if (!found) {
    selectedNodes.push_back(node);
  }

}



void GUINetwork::removeSelectedNode(GUINode *node) {

  for (list<GUINode*>::iterator iter = selectedNodes.begin(); 
       iter != selectedNodes.end(); iter++) {
    if ((*iter) == node) {
      (*iter)->unselect();
      selectedNodes.erase(iter);
      break;
    }
  }
}


void GUINetwork::popTooltip(GUINode *node)
{
   if (tooltip)
   {
      delete tooltip;
      tooltip=NULL;
   }
   if (node)
      tooltip = new GUINodeTooltip(node);
}

void GUINetwork::rename(string newName) {

  try {
    UINetwork::rename(newName);

    setModified();
  }
  catch (BaseException *e) {
    stringstream str;
    e->print(str);
    GtkWidget*  dialog = gnome_warning_dialog (str.str().c_str());
    delete e;
  }
  
}


static void network_properties_apply (GnomePropertyBox *propertybox, gint arg1, GUINetwork *net) {
  if (net) {
    net->applyNetworkProperties();
  }
}



void network_description_changed_event (GtkTextBuffer *textbuffer, GUINetwork *network) {  
  gnome_property_box_set_modified (GNOME_PROPERTY_BOX(network->networkProperties),TRUE);
}


void GUINetwork::showProperties() {

  if (networkProperties) {
    //destroy old network properties dialog
    gtk_widget_destroy(networkProperties);
  }
  
  networkProperties = gnome_property_box_new();  
  gtk_widget_ref (networkProperties);  


  GtkWidget *scrolled_window = gtk_scrolled_window_new (NULL, NULL);
  gtk_widget_ref (scrolled_window);
  gtk_object_set_data_full (GTK_OBJECT (networkProperties), "scrolled_window", scrolled_window,
                            (GtkDestroyNotify) gtk_widget_unref);
  gtk_widget_show (scrolled_window);
  gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window), GTK_POLICY_NEVER, GTK_POLICY_ALWAYS);


  GtkWidget *text_view = gtk_text_view_new ();
  gtk_widget_ref (text_view);

  //text view properties
  gtk_text_view_set_editable (GTK_TEXT_VIEW (text_view), TRUE);
  gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (text_view), GTK_WRAP_WORD);
  gtk_text_view_set_cursor_visible (GTK_TEXT_VIEW (text_view), TRUE);	 

  //set the description		   
  gtk_text_buffer_set_text (gtk_text_view_get_buffer (GTK_TEXT_VIEW (text_view)),
			    getDescription().c_str(), -1);

  gtk_object_set_data_full (GTK_OBJECT (networkProperties), "text_view", text_view,
                            (GtkDestroyNotify) gtk_widget_unref);
  gtk_widget_show (text_view);
  gtk_container_add (GTK_CONTAINER (scrolled_window), text_view);
  gtk_text_view_set_editable(GTK_TEXT_VIEW(text_view),TRUE);


  //description text signal handler
  g_object_connect (G_OBJECT (gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_view))), "signal::changed",
		    GTK_SIGNAL_FUNC(network_description_changed_event), this,NULL);



  GtkWidget *description_label = gtk_label_new (_("Description"));
  gtk_widget_ref (description_label);

  gtk_object_set_data_full (GTK_OBJECT (networkProperties), "description_label", description_label,
                            (GtkDestroyNotify) gtk_widget_unref);
  gtk_widget_show (description_label);
   
  //append "Description page"
  gnome_property_box_append_page  (GNOME_PROPERTY_BOX(networkProperties),scrolled_window, description_label);
  
  gtk_signal_connect (GTK_OBJECT (networkProperties), "apply", GTK_SIGNAL_FUNC(network_properties_apply), this);


  //default = nothing has changed
  gnome_property_box_set_modified (GNOME_PROPERTY_BOX(networkProperties),FALSE);

  //show properties dialog
  gtk_widget_show(networkProperties);

}




void GUINetwork::applyNetworkProperties() {

  if (networkProperties) {
    //updating description
    GtkTextView *text_view = GTK_TEXT_VIEW(gtk_object_get_data(GTK_OBJECT(networkProperties), "text_view"));
    GtkTextBuffer* buffer = gtk_text_view_get_buffer(text_view);
    GtkTextIter start, end;
    gtk_text_buffer_get_bounds(buffer, &start, &end);       
    setDescription(gtk_text_buffer_get_text (buffer, &start, &end, TRUE));    
    setModified();
  }
}


UINote* GUINetwork::newNote(const std::string &text, double x, double y, bool visible) {
  return new GUINote(text,x,y,visible,this);
}

void GUINetwork::auto_scroll(double x, double y) {
  //cerr<<"auto scroll x"<<x<<" y"<<y<<endl;


  int offset_x;
  int offset_y;

  gnome_canvas_get_scroll_offsets(canvas,&offset_x,&offset_y);

  double scroll_x1;
  double scroll_y1;
  double scroll_x2;
  double scroll_y2;
  
  gnome_canvas_get_scroll_region(canvas,&scroll_x1,&scroll_y1,&scroll_x2,&scroll_y2);

  GtkWidget*  hsbar = gtk_scrolled_window_get_hscrollbar (GTK_SCROLLED_WINDOW(scrolledwindow1));
  GtkWidget*  vsbar = gtk_scrolled_window_get_vscrollbar (GTK_SCROLLED_WINDOW(scrolledwindow1));
 
  GtkAdjustment* h_adj = gtk_range_get_adjustment(GTK_RANGE(hsbar));  
  double h_upper, h_lower, h_page_size;
  g_object_get(G_OBJECT(h_adj),"lower",&h_lower,"upper",&h_upper,"page_size",&h_page_size,NULL);
  //cerr<<"h_lower"<<h_lower<<" h_upper "<<h_upper<<"h_page_size "<<h_page_size<<endl;


  GtkAdjustment* v_adj = gtk_range_get_adjustment(GTK_RANGE(vsbar));  
  double v_upper, v_lower, v_page_size;
  g_object_get(G_OBJECT(v_adj),"lower",&v_lower,"upper",&v_upper,"page_size",&v_page_size,NULL);
  //cerr<<"v_lower"<<v_lower<<" v_upper "<<v_upper<<"v_page_size "<<v_page_size<<endl;

  int supp_offset_x = 0;
  int supp_offset_y = 0;

  //RIGHT BOUNDARY
  if (x > scroll_x1 + (double)(offset_x + h_page_size - 25))
  {
    //cerr<<"RIGHT BOUNDARY"<<endl;
    supp_offset_x += 10;
  }

  //LEFT BOUNDARY
  if ((scroll_x1 + offset_x + 25.0) > x) {
    //cerr<<"LEFT BOUNDARY"<<endl;    
    supp_offset_x -= 10;
  }

  //TOP BOUNDARY
  if ((scroll_y1 + offset_y + 25.0) > y) {
    //cerr<<"TOP BOUNDARY"<<endl;
    supp_offset_y -= 10;
  }

  //BOTTOM BOUNDARY
  if (y > scroll_y1 + (double) (offset_y + v_page_size - 25)) {
    //cerr<<"BOTTOM BOUNDARY"<<endl;
    supp_offset_y += 10;
  }
  
  if (supp_offset_x != 0 || supp_offset_y != 0) {
    gnome_canvas_scroll_to(canvas,offset_x + supp_offset_x, offset_y + supp_offset_y);
  }


}

void GUINetwork::get_visible_bounds(double &x1, double &y1, double &x2, double &y2) {

  int offset_x;
  int offset_y;

  gnome_canvas_get_scroll_offsets(canvas,&offset_x,&offset_y);

  double scroll_x1;
  double scroll_y1;
  double scroll_x2;
  double scroll_y2;
  
  gnome_canvas_get_scroll_region(canvas,&scroll_x1,&scroll_y1,&scroll_x2,&scroll_y2);

  GtkWidget*  hsbar = gtk_scrolled_window_get_hscrollbar (GTK_SCROLLED_WINDOW(scrolledwindow1));
  GtkWidget*  vsbar = gtk_scrolled_window_get_vscrollbar (GTK_SCROLLED_WINDOW(scrolledwindow1));
 
  GtkAdjustment* h_adj = gtk_range_get_adjustment(GTK_RANGE(hsbar));  
  double h_upper, h_lower, h_page_size;
  g_object_get(G_OBJECT(h_adj),"lower",&h_lower,"upper",&h_upper,"page_size",&h_page_size,NULL);
  


  GtkAdjustment* v_adj = gtk_range_get_adjustment(GTK_RANGE(vsbar));  
  double v_upper, v_lower, v_page_size;
  g_object_get(G_OBJECT(v_adj),"lower",&v_lower,"upper",&v_upper,"page_size",&v_page_size,NULL);
  
  x1 = scroll_x1 + offset_x;
  x2 = scroll_x1 + offset_x + h_page_size;

  y1 = scroll_y1 + offset_y;
  y2 = scroll_y1 + offset_y + v_page_size;


}


}//namespace FD


syntax highlighted by Code2HTML, v. 0.9.1