/*   EXTRAITS DE LA LICENCE
	Copyright CEA, contributeurs : Luc BILLARD et Damien
	CALISTE, laboratoire L_Sim, (2001-2006)
  
	Adresse mèl :
	BILLARD, non joignable par mèl ;
	CALISTE, damien P caliste AT cea P fr.

	Ce logiciel est un programme informatique servant à visualiser des
	structures atomiques dans un rendu pseudo-3D. 

	Ce logiciel est régi par la licence CeCILL soumise au droit français et
	respectant les principes de diffusion des logiciels libres. Vous pouvez
	utiliser, modifier et/ou redistribuer ce programme sous les conditions
	de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA 
	sur le site "http://www.cecill.info".

	Le fait que vous puissiez accéder à cet en-tête signifie que vous avez 
	pris connaissance de la licence CeCILL, et que vous en avez accepté les
	termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel).
*/

/*   LICENCE SUM UP
	Copyright CEA, contributors : Luc BILLARD et Damien
	CALISTE, laboratoire L_Sim, (2001-2006)

	E-mail address:
	BILLARD, not reachable any more ;
	CALISTE, damien P caliste AT cea P fr.

	This software is a computer program whose purpose is to visualize atomic
	configurations in 3D.

	This software is governed by the CeCILL  license under French law and
	abiding by the rules of distribution of free software.  You can  use, 
	modify and/ or redistribute the software under the terms of the CeCILL
	license as circulated by CEA, CNRS and INRIA at the following URL
	"http://www.cecill.info". 

	The fact that you are presently reading this means that you have had
	knowledge of the CeCILL license and that you accept its terms. You can
	find a copy of this licence shipped with this software at Documentation/licence.en.txt.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include "gtk_renderingWindowWidget.h"

#include <gtk/gtk.h>
#include <gdk/gdkkeysyms.h>
#include <math.h> /* for sqrt function... */

#if SYSTEM_X11 == 1
#include <gdk/gdkx.h>
#endif

#if SYSTEM_WIN32 == 1
#include <windows.h>
#include <gdk/gdk.h>


struct _GdkDrawableImplWin32
{
  GdkDrawable parent_instance;

  GdkDrawable *wrapper;

  GdkColormap *colormap;

  HANDLE handle;
};
typedef struct _GdkDrawableImplWin32 GdkDrawableImplWin32;
#endif

#include <pixmaps/icone-observe.xpm>

#include "support.h"
#include "visu_tools.h"
#include "visu_object.h"
#include "visu_data.h"
#include "visu_pickMesure.h"
#include "OSOpenGL/visu_OSInterface.h"
#include "renderingBackend/visu_actionInterface.h"
#include "gtk_main.h"
#include "extraGtkFunctions/gtk_dumpDialogWidget.h"
#include "openGLFunctions/objectList.h"
#include "opengl.h"


static void renderingWindow_class_init          (RenderingWindowClass *klass);
static void renderingWindow_init                (RenderingWindow *renderingWindow);
static void renderingWindow_destroy             (GtkObject *object);


GtkWindowClass *parent_class;

typedef enum
  {
    event_button_press,
    event_button_release,
    event_motion_notify,
    event_key_press,
    event_scroll
  } InteractiveEventsId;

struct InteractiveEvents_struct
{
  gulong callbackId;
  InteractiveEventsId id;
};
typedef struct InteractiveEvents_struct InteractiveEvents;


struct GtkInfoArea_struct
{
  GtkWidget *area;

  GtkWidget *hboxFileInfo;
  GtkWidget *eventsWarningSize;
  GtkWidget *labelSize;
  GtkWidget *labelNb;
  GtkWidget *labelFileInfo;
  gboolean fileInfoFreeze;

  GtkWidget *dumpButton;
  GtkWidget *loadButton;

  GtkWidget *statusInfo;
  guint statusInfoId;
};
typedef struct GtkInfoArea_struct GtkInfoArea;

#define GTK_STATUSINFO_NOFILEINFO _("<span style=\"italic\">No description is available</span>")
#define GTK_STATUSINFO_NONB       _("<span style=\"italic\">Nothing is loaded</span>")

/* Internal gtkStatusInfo functions. */
GtkInfoArea *gtkStatusInfo_createBar(RenderingWindow *window, gint width, gint height);
/**
 * gtkStatusInfo_showSizeWarning:
 * @info: the #GtkInfoArea that needs modifications ;
 * @bool: a boolean value.
 *
 * Set if a warning icon is display near the size infomation.
 */
void gtkStatusInfo_showSizeWarning(GtkInfoArea *info, gboolean bool);
/**
 * gtkStatusInfo_setOpenGLSize:
 * @info: the #GtkInfoArea that needs modifications ;
 * @width: size of the OpenGL area ;
 * @height: idem ;
 * @bool: TRUE if the label is printed in red (for warning reasons).
 *
 * Set the label of the size for the OpenGL area.
 */
void gtkStatusInfo_setOpenGLSize(GtkInfoArea *info, gint width, gint height, gboolean bool);
/**
 * gtkStatusInfo_setFileInfo:
 * @info: the #GtkInfoArea that needs modifications ;
 * @message: an UTF8 string to print on the status bar.
 *
 * Use this method to display the commentary associated to a file.
 */
void gtkStatusInfo_setFileDescription(GtkInfoArea *info, gchar *message);
/**
 * gtkStatusInfo_setNbNodes:
 * @info: the #GtkInfoArea that needs modifications ;
 * @nb: number of loaded nodes (-1 if no file loaded).
 *
 * Use this method to display the commentary associated to the number of allocated nodes.
 */
void gtkStatusInfo_setNbNodes(GtkInfoArea *info, gint nb);
/* Local callbacks */
void onFileInfoToggled(GtkToggleButton *button, gpointer data);
void onLoadFileClicked(RenderingWindow *window, gpointer data);
void onRefreshViewClicked(GtkButton *button, gpointer data);
static void onDumpButtonClicked(GtkButton *button, gpointer user_data);
void displayFileInfoOnDataLoaded(RenderingWindow *window);
void onRenderingMethodChanged(RenderingWindow *window, gpointer data);
void setDumpButtonSensitive(RenderingWindow *window);



struct RenderingWindow_struct
{
  GtkWindow topRenderedWindow;

  /*********************************/
  /* Dealing with the OpenGL area. */
  /*********************************/
  /* The OpenGL area and it's notification zone. */
  GtkWidget *eventOnOpenGl;
  GtkWidget *socketOpenGL;
  /* Stored size of the OpenGL area. */
  gint socketWidth, socketHeight;
  /* A flag to store if the rendering window
     is in an interactive mode. */
  gboolean interactiveModeIsActive;
  /* A flag to prevent default interactive
     mode to bring up on signals. */
  gboolean interactiveModeIsBlocked;
  /* This pointer give the possibility to store
     several picked nodes and manage marks on them. */
  PickMesure *pickMesure;
  /* This is a list of currently connected
     signal for the interactive mode. */
  GList *interactiveEventsId;
  /* A pointer on the current used cursor. */
  GdkCursor *currentCursor;
  /* Callbacks associated to interactive mode. */
  CallbackFunctions callbacksInInteractiveMode;
  /* A pixbuf that can be display in the OpenGL area. */
  GdkPixbuf *backLogo;


  /*************************************/
  /* Dealing with the information bar. */
  /*************************************/
  /* TO BE INTEGRATED. */
  GtkInfoArea *info;
  /* TO BE INTEGRATED. */
  int nbStatusMessage;


  /* External method exposure signal id. */
  gulong exposureEventId;
  GCallback exposureCallback;

  /* a pointer to the currently loaded VisuData. */
  VisuData *currentData;
};

struct RenderingWindowClass_struct
{
  GtkWindowClass parent_class;

  void (*renderingWindow) (RenderingWindow *window);

  GdkCursor *cursorRotate;
  GdkCursor *cursorWatch;
  GdkCursor *cursorPointer;
  GdkCursor *cursorPirate;
  GdkCursor *currentCursor;
};

/* Local callbacks */
gboolean onKillRenderingWindowEvent(GtkWidget *widget, GdkEvent *event, gpointer user_data);
gboolean onVisibility(GtkWidget *widget, GdkEventVisibility *event, gpointer user_data);
/* Alert user when size of the OpenGL area is changed. */
static void onSizeChangeEvent(GtkWidget *widget, GtkAllocation *allocation, gpointer user_data);

/* Interactive mode listeners. */
static gboolean onKeyPressed(GtkWidget *widget, GdkEventKey *event, gpointer user_data);
static gboolean onMouseMotion(GtkWidget *widget, GdkEventMotion *event, gpointer user_data);
static gboolean onScrollEvent(GtkWidget *widget, GdkEventScroll *event, gpointer user_data);
static gboolean onButtonAction(RenderingWindow *window, GdkEventButton *event, gpointer user_data);


GType renderingWindow_get_type(void)
{
  static GType renderingWindow_type = 0;

  if (!renderingWindow_type)
    {
      static const GTypeInfo renderingWindow_info =
      {
        sizeof (RenderingWindowClass),
        NULL, /* base_init */
        NULL, /* base_finalize */
        (GClassInitFunc) renderingWindow_class_init,
        NULL, /* class_finalize */
        NULL, /* class_data */
        sizeof (RenderingWindow),
        0,
        (GInstanceInitFunc) renderingWindow_init,
	0
      };
      renderingWindow_type = g_type_register_static(GTK_TYPE_WINDOW, "RenderingWindow",
						    &renderingWindow_info, 0);
      DBG_fprintf(stderr, "Gtk RenderingWindow : creating the type RenderingWindow %p.\n",
		  (gpointer)renderingWindow_type);
    }

  return renderingWindow_type;
}

static void renderingWindow_class_init(RenderingWindowClass *klass)
{
  DBG_fprintf(stderr, "Gtk RenderingWindow : creating the class of the widget.\n");

  parent_class = g_type_class_peek_parent(klass);
  
  /* Initialisation des crseurs utiles. */
  klass->cursorPirate = gdk_cursor_new(GDK_PIRATE);
  klass->cursorRotate = gdk_cursor_new(GDK_BOX_SPIRAL);
  klass->cursorWatch = gdk_cursor_new(GDK_WATCH);
  klass->cursorPointer = gdk_cursor_new(GDK_DOTBOX);
}

static void renderingWindow_init(RenderingWindow *renderingWindow)
{
  DBG_fprintf(stderr, "Gtk RenderingWindow : initializing new object (%p).\n",
	      (gpointer)renderingWindow);

  renderingWindow->currentData = (VisuData*)0;
}


GtkWidget* renderingWindow_new(char* windowRef, char* window_name,
			       char* class_name, int width, int height)
{
  RenderingWindow *renderingWindow;

  GdkPixbuf *iconPixBuf;
  GtkWidget *wd, *vbox;
  int res;
#if SYSTEM_WIN32 == 1
  gpointer windowHandler;
  GdkDrawable *impl;
  GtkWidget *winst, *vbox2;
#endif
#if SYSTEM_X11 == 1
  XID XWindowId;
  XSetWindowAttributes wattrs;
#endif


  DBG_fprintf(stderr, "Gtk RenderingWindow : creating a new RenderingWindow object.\n");

  renderingWindow = RENDERING_WINDOW(g_object_new(renderingWindow_get_type(), NULL));

  /* We create the rendering window. */
  gtk_window_set_title(GTK_WINDOW(renderingWindow), windowRef);
  gtk_window_set_wmclass(GTK_WINDOW(renderingWindow), window_name, class_name);
  g_signal_connect(G_OBJECT(renderingWindow), "delete-event",
		   G_CALLBACK(onKillRenderingWindowEvent), (gpointer)0);
  g_signal_connect(G_OBJECT(renderingWindow), "destroy-event",
		   G_CALLBACK(onKillRenderingWindowEvent), (gpointer)0);
  iconPixBuf = gdk_pixbuf_new_from_xpm_data((const char**)icone_observe_xpm);
  gtk_window_set_icon(GTK_WINDOW(renderingWindow), iconPixBuf);

  vbox = gtk_vbox_new(FALSE, 0);
  gtk_container_add(GTK_CONTAINER(renderingWindow), vbox);
  gtk_widget_show(vbox);

#if SYSTEM_WIN32 == 1
  /* We create a window to store the status bar. */
  winst = gtk_window_new(GTK_WINDOW_TOPLEVEL);
  gtk_window_set_title(GTK_WINDOW(winst), _("Status info"));
  gtk_window_set_wmclass(GTK_WINDOW(winst), window_name, class_name);
  g_signal_connect(G_OBJECT(winst), "delete-event",
		   G_CALLBACK(onKillRenderingWindowEvent), (gpointer)0);
  g_signal_connect(G_OBJECT(winst), "destroy-event",
		   G_CALLBACK(onKillRenderingWindowEvent), (gpointer)0);
  gtk_widget_set_size_request(winst, width, -1);
  gtk_widget_show(winst);

  vbox2 = gtk_vbox_new(FALSE, 0);
  gtk_container_add(GTK_CONTAINER(winst), vbox2);
  gtk_widget_show(vbox2);
#endif

  /* We create the statusinfo area. */
  renderingWindow->info = gtkStatusInfo_createBar(renderingWindow, width, height);
  wd = renderingWindow->info->area;
#if SYSTEM_X11 == 1
  gtk_box_pack_end(GTK_BOX(vbox), wd, FALSE, FALSE, 0);
#endif
#if SYSTEM_WIN32 == 1
  gtk_box_pack_end(GTK_BOX(vbox2), wd, FALSE, FALSE, 0);
#endif
  gtk_widget_show_all(wd);
  gtkStatusInfo_showSizeWarning(renderingWindow->info, FALSE);

  /* We put on the event listener for the OpenGL area. */
  renderingWindow->eventOnOpenGl = gtk_event_box_new();
  /* the GDK_POINTER_MOTION_HINT_MASK is necessary to let the
     program redraw the window before listening to motion-event again. */
  gtk_widget_set_events(renderingWindow->eventOnOpenGl,
			GDK_BUTTON_PRESS_MASK |
			GDK_BUTTON_RELEASE_MASK |
			GDK_SCROLL_MASK |
			GDK_KEY_PRESS_MASK |
			GDK_POINTER_MOTION_MASK |
			GDK_POINTER_MOTION_HINT_MASK |
			GDK_VISIBILITY_NOTIFY_MASK);
  gtk_box_pack_start(GTK_BOX(vbox), renderingWindow->eventOnOpenGl, TRUE, TRUE, 0);
  gtk_widget_show(renderingWindow->eventOnOpenGl);
  
  /* We create the socket that own the OpenGL rendering zone. */
#if SYSTEM_X11 == 1
  renderingWindow->socketOpenGL = gtk_socket_new();
#endif
#if SYSTEM_WIN32 == 1
  renderingWindow->socketOpenGL = gtk_label_new("V_Sim");
#endif
  gtk_container_add(GTK_CONTAINER(renderingWindow->eventOnOpenGl),
		    renderingWindow->socketOpenGL);
  gtk_widget_set_size_request(renderingWindow->socketOpenGL, width, height);
  gtk_widget_show(renderingWindow->socketOpenGL);

  /* We physically show the window. */
  gtk_widget_show(GTK_WIDGET(renderingWindow));

  gdk_window_set_cursor(GDK_WINDOW(renderingWindow->socketOpenGL->window),
			RENDERING_WINDOW_CLASS(G_OBJECT_GET_CLASS(renderingWindow))->cursorPirate);

  /* Unset the size request. */
  gtk_widget_set_size_request(renderingWindow->socketOpenGL, 30, 30);
  renderingWindow->socketWidth = width;
  renderingWindow->socketHeight = height;
  /* Set a listener on the size to show the warning icon accordingly. */
  g_signal_connect(G_OBJECT(renderingWindow->socketOpenGL), "size-allocate",
		   G_CALLBACK(onSizeChangeEvent), (gpointer)renderingWindow);

  res = 0;
#if SYSTEM_X11 == 1
  res = setDisplay((gpointer)gdk_x11_drawable_get_xdisplay(GDK_DRAWABLE(renderingWindow->socketOpenGL->window)));
  res = setScreen(gdk_x11_screen_get_screen_number(gdk_drawable_get_screen(GDK_DRAWABLE(renderingWindow->socketOpenGL->window)))) || res;
  XWindowId = gdk_x11_drawable_get_xid(GDK_DRAWABLE(renderingWindow->socketOpenGL->window));
  res = setWindowHandler((gpointer)&XWindowId) || res;
#endif
#if SYSTEM_WIN32 == 1
  impl = ((GdkWindowObject*)renderingWindow->socketOpenGL->window)->impl;
  windowHandler = &((GdkDrawableImplWin32*)impl)->handle;
  res = setWindowHandler(windowHandler);
  res = initDisplay() || res;
#endif

  res = initOpenGLContext() || res;

  /* Now that the glx tunnel has been added, we need
     to specify again that we want a backing store because until now
     the backing store is only for the X window (and thus is black)
     but not for the glx screen. */
#if SYSTEM_X11 == 1
  wattrs.backing_store = Always;
  XChangeWindowAttributes(gdk_x11_drawable_get_xdisplay(GDK_DRAWABLE(renderingWindow->socketOpenGL->window)), XWindowId, CWBackingStore, &wattrs);
#endif

  /* Set local variables. */
  renderingWindow->interactiveModeIsActive = FALSE;
  renderingWindow->nbStatusMessage = 0;
  renderingWindow->interactiveEventsId = (GList*)0;
  renderingWindow->currentCursor = 
    RENDERING_WINDOW_CLASS(G_OBJECT_GET_CLASS(renderingWindow))->cursorPirate;
  renderingWindow->backLogo = (GdkPixbuf*)0;
  renderingWindow->interactiveModeIsBlocked = FALSE;
  renderingWindow->pickMesure = (PickMesure*)0;
  renderingWindow->exposureEventId = (gulong)0;
  renderingWindow->exposureCallback = (GCallback)0;

  DBG_fprintf(stderr, "Visu window GTK : Building OK.\n");

  return GTK_WIDGET(renderingWindow);
}

GtkInfoArea *gtkStatusInfo_createBar(RenderingWindow *window, gint width, gint height)
{
  GtkWidget *hbox, *vbox;
  GtkWidget *wd, *image;
  GtkTooltips *tooltips;
  GString *str;
  GtkInfoArea *info;

  GtkWidget *handle, *hboxHandle;

  info = g_malloc(sizeof(GtkInfoArea));

  info->area = gtk_vbox_new(FALSE, 0);

  tooltips = gtk_tooltips_new ();

  info->fileInfoFreeze = FALSE;
  info->hboxFileInfo = gtk_hbox_new(FALSE, 0);
  gtk_box_pack_start(GTK_BOX(info->area), info->hboxFileInfo, FALSE, FALSE, 1);

  /* Size info */
  wd = gtk_hbox_new(FALSE, 0);
  gtk_box_pack_start(GTK_BOX(info->hboxFileInfo), wd, FALSE, FALSE, 5);
  info->eventsWarningSize = gtk_event_box_new();
  gtk_tooltips_set_tip (tooltips, info->eventsWarningSize,
			_("The size of the window has changed. Click"
			  " on the 'refresh' button for changes to"
			  " be applied to the OpenGL area."), NULL);
  gtk_box_pack_start(GTK_BOX(wd), info->eventsWarningSize, FALSE, FALSE, 0);
  image = gtk_image_new_from_stock(GTK_STOCK_DIALOG_WARNING,
				   GTK_ICON_SIZE_MENU);
  gtk_container_add(GTK_CONTAINER(info->eventsWarningSize), image);
  info->labelSize = gtk_label_new("");
  gtk_label_set_use_markup(GTK_LABEL(info->labelSize), TRUE);
  gtkStatusInfo_setOpenGLSize(info, width, height, FALSE);
  gtk_box_pack_start(GTK_BOX(wd), info->labelSize, FALSE, FALSE, 0);

  wd = gtk_vseparator_new();
  gtk_box_pack_start(GTK_BOX(info->hboxFileInfo), wd, FALSE, FALSE, 0);

  /* Nb nodes */
  info->labelNb = gtk_label_new("");
  gtk_label_set_use_markup(GTK_LABEL(info->labelNb), TRUE);
  gtkStatusInfo_setNbNodes(info, -1);
  gtk_box_pack_start(GTK_BOX(info->hboxFileInfo), info->labelNb, FALSE, FALSE, 5);

  wd = gtk_vseparator_new();
  gtk_box_pack_start(GTK_BOX(info->hboxFileInfo), wd, FALSE, FALSE, 0);

  /* File info */
  wd = gtk_hbox_new(FALSE, 0);
  gtk_box_pack_start(GTK_BOX(info->hboxFileInfo), wd, TRUE, TRUE, 5);
  image = gtk_image_new_from_stock(GTK_STOCK_SAVE,
				   GTK_ICON_SIZE_MENU);
  gtk_box_pack_start(GTK_BOX(wd), image, FALSE, FALSE, 1);
  info->labelFileInfo = gtk_label_new("");
  gtk_label_set_use_markup(GTK_LABEL(info->labelFileInfo), TRUE);
  gtk_misc_set_alignment(GTK_MISC(info->labelFileInfo), 0., 0.5);
#if GTK_MINOR_VERSION > 5
  gtk_label_set_ellipsize(GTK_LABEL(info->labelFileInfo), PANGO_ELLIPSIZE_END);
#endif
  gtkStatusInfo_setFileDescription(info, GTK_STATUSINFO_NOFILEINFO);
  gtk_box_pack_start(GTK_BOX(wd), info->labelFileInfo, TRUE, TRUE, 0);

  /* Status */
  hbox = gtk_hbox_new(FALSE, 0);
  gtk_box_pack_start(GTK_BOX(info->area), hbox, FALSE, FALSE, 0);

  /* Handle box for action buttons. */
  handle = gtk_handle_box_new();
  gtk_box_pack_start(GTK_BOX(hbox), handle, FALSE, FALSE, 0);
  hboxHandle = gtk_hbox_new(TRUE, 1);
  gtk_container_add(GTK_CONTAINER(handle), hboxHandle);
  /* Load button */
  info->loadButton = gtk_button_new();
  gtk_widget_set_sensitive(info->loadButton, FALSE);
  gtk_tooltips_set_tip (tooltips, info->loadButton,
			_("Open"), NULL);
  g_signal_connect_swapped(G_OBJECT(info->loadButton), "clicked",
			   G_CALLBACK(onLoadFileClicked), (gpointer)window);
  image = gtk_image_new_from_stock(GTK_STOCK_OPEN,
				   GTK_ICON_SIZE_MENU);
  gtk_container_add(GTK_CONTAINER(info->loadButton), image);
  gtk_box_pack_start(GTK_BOX(hboxHandle), info->loadButton, FALSE, FALSE, 0);
  /* Refresh button */
  wd = gtk_button_new();
  gtk_tooltips_set_tip (tooltips, wd,
			_("Refresh"), NULL);
  g_signal_connect(G_OBJECT(wd), "clicked",
		   G_CALLBACK(onRefreshViewClicked), (gpointer)window);
  image = gtk_image_new_from_stock(GTK_STOCK_REFRESH,
				   GTK_ICON_SIZE_MENU);
  gtk_container_add(GTK_CONTAINER(wd), image);
  gtk_box_pack_start(GTK_BOX(hboxHandle), wd, FALSE, FALSE, 0);
  /* Save button */
  info->dumpButton = gtk_button_new();
  gtk_tooltips_set_tip (tooltips, info->dumpButton,
			_("Export"), NULL);
  g_signal_connect(G_OBJECT(info->dumpButton), "clicked",
		   G_CALLBACK(onDumpButtonClicked), (gpointer)window);
  gtk_widget_set_sensitive(info->dumpButton, FALSE);
  image = gtk_image_new_from_stock(GTK_STOCK_SAVE_AS,
				   GTK_ICON_SIZE_MENU);
  gtk_container_add(GTK_CONTAINER(info->dumpButton), image);
  gtk_box_pack_start(GTK_BOX(hboxHandle), info->dumpButton, FALSE, FALSE, 0);

  /* Hide button */
  wd = gtk_toggle_button_new();
  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(wd), TRUE);
  g_object_set(G_OBJECT(wd), "can-default", FALSE, "can-focus", FALSE,
	       "has-default", FALSE, "has-focus", FALSE, NULL);
  g_signal_connect(G_OBJECT(wd), "toggled",
		   G_CALLBACK(onFileInfoToggled), (gpointer)window);
  gtk_tooltips_set_tip (tooltips, wd,
			_("Show/hide miscellaneous informations."), NULL);
  image = gtk_image_new_from_stock(GTK_STOCK_DIALOG_QUESTION,
				   GTK_ICON_SIZE_MENU);
  gtk_container_add(GTK_CONTAINER(wd), image);
  gtk_box_pack_start(GTK_BOX(hbox), wd, FALSE, FALSE, 5);

  info->statusInfo = gtk_statusbar_new();
  gtk_box_pack_start(GTK_BOX(hbox), info->statusInfo, TRUE, TRUE, 0);
  gtk_statusbar_set_has_resize_grip(GTK_STATUSBAR(info->statusInfo), FALSE);

  info->statusInfoId = gtk_statusbar_get_context_id(GTK_STATUSBAR(info->statusInfo),
						    "OpenGL statusbar.");
  
  g_signal_connect_swapped(G_OBJECT(visu), "renderingChanged",
			   G_CALLBACK(onRenderingMethodChanged), (gpointer)window);

  return info;
}


gboolean onKillRenderingWindowEvent(GtkWidget *widget, GdkEvent *event, gpointer user_data)
{
  DBG_fprintf(stderr, "Gtk RenderingWindow : delete or destroy event cancelled.\n");
  return TRUE;
}

gboolean onVisibility(GtkWidget *widget, GdkEventVisibility *event, gpointer user_data)
{
  g_return_val_if_fail(user_data, TRUE);

  DBG_fprintf(stderr, "Gtk RenderingWindow : visibility event catched.\n");
  if (event->state == GDK_VISIBILITY_UNOBSCURED &&
      RENDERING_WINDOW(user_data)->exposureCallback)
    RENDERING_WINDOW(user_data)->exposureCallback();
  return TRUE;
}
void renderingWindowConnect_exposureSignal(RenderingWindow *window, GCallback callback)
{
  g_return_if_fail(window && callback);

  renderingWindowDisconnect_exposureSignal(window);

  window->exposureCallback = callback;
  window->exposureEventId =
    g_signal_connect(G_OBJECT(window->eventOnOpenGl), "visibility-notify-event",
		     G_CALLBACK(onVisibility), (gpointer)window);
  DBG_fprintf(stderr, "Gtk RenderingWindow : connecting exposure callback %ld.\n",
		  window->exposureEventId);
}
void renderingWindowDisconnect_exposureSignal(RenderingWindow *window)
{
  g_return_if_fail(window);

  if (window->exposureEventId)
    {
      DBG_fprintf(stderr, "Gtk RenderingWindow : disconnecting exposure callback %ld.\n",
		  window->exposureEventId);
      g_signal_handler_disconnect(G_OBJECT(window->eventOnOpenGl), window->exposureEventId);
    }

  window->exposureEventId = (gulong)0;
}

gboolean updateOpenGLAreaSize(gpointer data)
{
  unsigned int w, h;
  RenderingWindow *window;

  window = RENDERING_WINDOW(data);
  g_return_val_if_fail(window, FALSE);

  renderingWindowGet_openGLAreaSize(window, &w, &h);
  if (window->currentData)
    visuDataSet_sizeOfView(window->currentData, w, h);
  else
    OpenGLViewSet_windowSize((OpenGLView*)0, w, h);
  gtkStatusInfo_showSizeWarning(window->info, FALSE);
  gtkStatusInfo_setOpenGLSize(window->info, w, h, FALSE);
  g_signal_emit (visu, VISU_GET_CLASS (visu)->OpenGLForceReDraw_signal_id,
		 0 , NULL);
  return FALSE;
}

static void onSizeChangeEvent(GtkWidget *widget, GtkAllocation *allocation, gpointer user_data)
{
  RenderingWindow *window;

  window = RENDERING_WINDOW(user_data);
  g_return_if_fail(window);

  /* Return if no changes in size (this event is called even the size
     is not really changed but has been negociated. */
  if (window->socketWidth == allocation->width &&
      window->socketHeight == allocation->height)
    return;

  /* If no data are currently rendered on this window,
     we can without lag update the size on the fly. */
  if (!window->currentData)
    {
      window->socketWidth = allocation->width;
      window->socketHeight = allocation->height;
      g_idle_add(updateOpenGLAreaSize, user_data);
      return;
    }
  
  /* If size has changed, we doesn't refresh automatically
     to avoid lag in window resizing if the OpenGL is
     heavy to redraw. We just print a warning message. */
  gtkStatusInfo_showSizeWarning(window->info, TRUE);
  window->socketWidth = allocation->width;
  window->socketHeight = allocation->height;
  gtkStatusInfo_setOpenGLSize(window->info,
			      window->socketWidth,
			      window->socketHeight, TRUE);
}


void minimalPickInfo(const VisuPick *info, gpointer data)
{
  float posSelect[3], posRef[3], dist;
  GString *str;
  RenderingWindow *window;
  VisuNode *node, *ref;
  int i;

  window = RENDERING_WINDOW(data);
  g_return_if_fail(window && window->pickMesure);

  while (window->nbStatusMessage > 1)
    {
      renderingWindowPop_message(window);
      window->nbStatusMessage -= 1;
    }

  marksAndMesures(info, window->pickMesure);
  if (pickMesureGet_newsAvailable(window->pickMesure))
    {
      node = pickMesureGet_selectedNode(window->pickMesure);
      ref = pickMesureGet_firstReference(window->pickMesure);

      /* No ref, then only position informations are displayed */
      if (!ref && node)
	{
	  visuDataGet_nodePosition(window->currentData, node, posSelect);
	  str = g_string_new(_("Selected node number "));
	  g_string_append_printf(str, "%d - (x, y, z) = (%7.3f;%7.3f;%7.3f)", node->number,
				 posSelect[0], posSelect[1], posSelect[2]);
	  renderingWindowPush_message(window, str->str);
	  window->nbStatusMessage += 1;
	  g_string_free(str, TRUE);
	}
      /* Have a ref and a selected node, then distance informations is compued. */
      if (ref && node)
	{
	  visuDataGet_nodePosition(window->currentData, node, posSelect);
	  visuDataGet_nodePosition(window->currentData, ref, posRef);
	  str = g_string_new(_("Distance between nodes "));
	  dist = 0.;
	  for (i = 0; i < 3; i++)
	    dist += (posRef[i] - posSelect[i]) * (posRef[i] - posSelect[i]);
	  dist = sqrt(dist);
	  g_string_append_printf(str, _("%d and %d : %7.3f"),
				 ref->number, node->number, dist);
	  renderingWindowPush_message(window, str->str);
	  window->nbStatusMessage += 1;
	  g_string_free(str, TRUE);
	}
      /* Have a ref only, give some text info. */
      if (ref && !node)
	{
	  renderingWindowPush_message(window, _("<shift> right-clic on background to unset reference"));
	  window->nbStatusMessage += 1;
	}
    }
}

void emptyInteractiveEventListeners(RenderingWindow *window)
{
  GList* ptList;

  g_return_if_fail(IS_RENDERING_WINDOW(window));

  DBG_fprintf(stderr, "Gtk RenderingWindow : removing current interactive listeners.\n");
  ptList = window->interactiveEventsId;
  while (ptList)
    {
      DBG_fprintf(stderr, "  | disconnecting %ld signal.\n", *(gulong*)ptList->data);
      g_signal_handler_disconnect(G_OBJECT(window->eventOnOpenGl), *(gulong*)ptList->data);
      g_free(ptList->data);
      ptList = g_list_next(ptList);
    }
  if (window->interactiveEventsId)
    g_list_free(window->interactiveEventsId);
  window->interactiveEventsId = (GList*)0;
}
gulong addInteractiveEventListeners(RenderingWindow *window, InteractiveEventsId id)
{
  GList* ptList;
  InteractiveEvents *event;
  gboolean found;

  g_return_val_if_fail(IS_RENDERING_WINDOW(window), (gulong)0);

  found  = FALSE;
  for (ptList = window->interactiveEventsId; ptList && !found; ptList = g_list_next(ptList))
    {
      event = (InteractiveEvents*)ptList->data;
      if (event->id == id)
	found = TRUE;
    }
  if (found)
    return (gulong)0;

  event = g_malloc(sizeof(InteractiveEvents));
  event->id = id;
  switch (id)
    {
    case event_button_press:
      event->callbackId = g_signal_connect_swapped(G_OBJECT(window->eventOnOpenGl),
						   "button-press-event",
						   G_CALLBACK(onButtonAction), (gpointer)window);
      break;
    case event_button_release:
      event->callbackId = g_signal_connect_swapped(G_OBJECT(window->eventOnOpenGl),
						   "button-release-event",
						   G_CALLBACK(onButtonAction), (gpointer)window);
      break;
    case event_motion_notify:
      event->callbackId = g_signal_connect(G_OBJECT(window->eventOnOpenGl),
					   "motion-notify-event",
					   G_CALLBACK(onMouseMotion), (gpointer)window);
      break;
    case event_key_press:
      event->callbackId = g_signal_connect(G_OBJECT(window->eventOnOpenGl),
					   "key-press-event",
					   G_CALLBACK(onKeyPressed), (gpointer)window);
      break;
    case event_scroll:
      event->callbackId = g_signal_connect(G_OBJECT(window->eventOnOpenGl),
					   "scroll-event",
					   G_CALLBACK(onScrollEvent), (gpointer)window);
      break;
    default:
      g_warning("Unknown event to add.");
      g_free(event);
      return (gulong)0;
    };
  window->interactiveEventsId = g_list_prepend(window->interactiveEventsId,
					       (gpointer)event);
  return event->callbackId;
}
gulong removeInteractiveEventListeners(RenderingWindow *window, InteractiveEventsId id)
{
  GList* ptList;
  InteractiveEvents *event;
  gulong callid;

  g_return_val_if_fail(IS_RENDERING_WINDOW(window), (gulong)0);

  for (ptList = window->interactiveEventsId; ptList; ptList = g_list_next(ptList))
    {
      event = (InteractiveEvents*)ptList->data;
      if (event->id == id)
	{
	  g_signal_handler_disconnect(G_OBJECT(window->eventOnOpenGl),
				      event->callbackId);
	  window->interactiveEventsId = g_list_remove(window->interactiveEventsId,
						      (gpointer)event);
	  callid = event->callbackId;
	  g_free(event);
	  return callid;
	}
    }
  return (gulong)0;
}
void renderingWindowRemove_interactiveEventListener(RenderingWindow *window)
{
  emptyInteractiveEventListeners(window);
  gdk_window_set_cursor(GDK_WINDOW(window->socketOpenGL->window),
			RENDERING_WINDOW_CLASS(G_OBJECT_GET_CLASS(window))->cursorPirate);
  window->currentCursor = RENDERING_WINDOW_CLASS(G_OBJECT_GET_CLASS(window))->cursorPirate;
}
void renderingWindowSet_observeEventListener(RenderingWindow *window,
					     CallbackFunctions *userCallbacks)
{
  gulong id;

  g_return_if_fail(IS_RENDERING_WINDOW(window) && userCallbacks && userCallbacks->action);

  gdk_window_set_cursor(GDK_WINDOW(window->socketOpenGL->window),
			RENDERING_WINDOW_CLASS(G_OBJECT_GET_CLASS(window))->cursorRotate);
  window->currentCursor = RENDERING_WINDOW_CLASS(G_OBJECT_GET_CLASS(window))->cursorRotate;

  DBG_fprintf(stderr, "Gtk RenderingWindow : setting current interactive listeners.\n");
  id = removeInteractiveEventListeners(window, event_button_release);
  if (id)
    DBG_fprintf(stderr, "  | disconnecting %ld signal.\n", id);
  id = addInteractiveEventListeners(window, event_button_press);
  if (id)
    DBG_fprintf(stderr, "  | connecting %ld signal.\n", id);
  id = addInteractiveEventListeners(window, event_motion_notify);
  if (id)
    DBG_fprintf(stderr, "  | connecting %ld signal.\n", id);
  id = addInteractiveEventListeners(window, event_key_press);
  if (id)
    DBG_fprintf(stderr, "  | connecting %ld signal.\n", id);
  id = addInteractiveEventListeners(window, event_scroll);
  if (id)
    DBG_fprintf(stderr, "  | connecting %ld signal.\n", id);
      
  window->callbacksInInteractiveMode.action = userCallbacks->action;
  window->callbacksInInteractiveMode.stop = userCallbacks->stop;
}
void renderingWindowSet_pickEventListener(RenderingWindow *window,
					  CallbackFunctions *userCallbacks)
{
  gulong id;

  g_return_if_fail(IS_RENDERING_WINDOW(window) && userCallbacks && userCallbacks->action);

  gdk_window_set_cursor(GDK_WINDOW(window->socketOpenGL->window),
			RENDERING_WINDOW_CLASS(G_OBJECT_GET_CLASS(window))->cursorPointer);
  window->currentCursor = RENDERING_WINDOW_CLASS(G_OBJECT_GET_CLASS(window))->cursorPointer;

  DBG_fprintf(stderr, "Gtk RenderingWindow : setting current interactive listeners.\n");
  id = addInteractiveEventListeners(window, event_button_press);
  if (id)
    DBG_fprintf(stderr, "  | connecting %ld signal.\n", id);
  id = addInteractiveEventListeners(window, event_button_release);
  if (id)
    DBG_fprintf(stderr, "  | connecting %ld signal.\n", id);
  id = addInteractiveEventListeners(window, event_motion_notify);
  if (id)
    DBG_fprintf(stderr, "  | connecting %ld signal.\n", id);
  id = removeInteractiveEventListeners(window, event_key_press);
  if (id)
    DBG_fprintf(stderr, "  | disconnecting %ld signal.\n", id);
  id = removeInteractiveEventListeners(window, event_scroll);
  if (id)
    DBG_fprintf(stderr, "  | disconnecting %ld signal.\n", id);
/*   id = addInteractiveEventListeners(window, event_key_press); */
/*   if (id) */
/*     DBG_fprintf(stderr, "  | connecting %ld signal.\n", id); */
/*   id = addInteractiveEventListeners(window, event_scroll); */
/*   if (id) */
/*     DBG_fprintf(stderr, "  | connecting %ld signal.\n", id); */
      
  window->callbacksInInteractiveMode.action = userCallbacks->action;
  window->callbacksInInteractiveMode.stop = userCallbacks->stop;
}

static gboolean onButtonAction(RenderingWindow *window, GdkEventButton *event, gpointer user_data)
{
  SimplifiedEvents ev;

  ev.button = 0;
  ev.motion = 0;
  ev.letter = '\0';

  gdk_window_set_cursor(GDK_WINDOW(window->socketOpenGL->window),
			RENDERING_WINDOW_CLASS(G_OBJECT_GET_CLASS(window))->cursorWatch);
  ev.x = event->x;
  ev.y = event->y;
  ev.button = event->button;
  ev.shiftMod = event->state & GDK_SHIFT_MASK;
  ev.controlMod = event->state & GDK_CONTROL_MASK;
  ev.buttonType = 0;
  if (event->type == GDK_BUTTON_PRESS)
    ev.buttonType = BUTTON_TYPE_PRESS;
  else if (event->type == GDK_BUTTON_RELEASE)
    ev.buttonType = BUTTON_TYPE_RELEASE;

  if (window->callbacksInInteractiveMode.action(&ev, window->currentData) &&
      window->callbacksInInteractiveMode.stop)
    window->callbacksInInteractiveMode.stop((gpointer)0);

  gdk_window_set_cursor(GDK_WINDOW(window->socketOpenGL->window),
			window->currentCursor);

  return TRUE;
}
static gboolean onButtonReleased(GtkWidget *widget, GdkEventButton *event, gpointer user_data)
{
}
static gboolean onScrollEvent(GtkWidget *widget, GdkEventScroll *event, gpointer user_data)
{
  SimplifiedEvents ev;
  RenderingWindow *window;

  window = RENDERING_WINDOW(user_data);
  g_return_val_if_fail(window, TRUE);

  ev.button = 0;
  ev.motion = 0;
  ev.letter = '\0';

  ev.x = event->x;
  ev.y = event->y;
  if (event->direction == GDK_SCROLL_UP)
    ev.button = 4;
  else if (event->direction == GDK_SCROLL_DOWN)
    ev.button = 5;
  ev.shiftMod = event->state & GDK_SHIFT_MASK;
  ev.controlMod = event->state & GDK_CONTROL_MASK;

  if (ev.button)
    {
      gdk_window_set_cursor(GDK_WINDOW(window->socketOpenGL->window),
			RENDERING_WINDOW_CLASS(G_OBJECT_GET_CLASS(window))->cursorWatch);
      window->callbacksInInteractiveMode.action(&ev, window->currentData);
      gdk_window_set_cursor(GDK_WINDOW(window->socketOpenGL->window),
			window->currentCursor);
    }

  return TRUE;
}
static gboolean onMouseMotion(GtkWidget *widget, GdkEventMotion *event, gpointer user_data)
{
  GdkWindow *windowMove;
  gint x, y;
  GdkModifierType mask;
  SimplifiedEvents ev;
  RenderingWindow *window;

  window = RENDERING_WINDOW(user_data);
  g_return_val_if_fail(window, TRUE);

  ev.button = 0;
  ev.motion = 1;
  ev.letter = '\0';

  windowMove = gdk_window_get_pointer(GDK_WINDOW(window->socketOpenGL->window),
				      &x, &y, &mask);

  ev.x = x;
  ev.y = y;
  if (event->state & GDK_BUTTON1_MASK)
    ev.button = 1;
  else if (event->state & GDK_BUTTON2_MASK)
    ev.button = 2;
  else if (event->state & GDK_BUTTON3_MASK)
    ev.button = 3;
  ev.shiftMod = event->state & GDK_SHIFT_MASK;
  ev.controlMod = event->state & GDK_CONTROL_MASK;

  if (ev.button == 1 || ev.button == 2)
    {
      gdk_window_set_cursor(GDK_WINDOW(window->socketOpenGL->window),
			RENDERING_WINDOW_CLASS(G_OBJECT_GET_CLASS(window))->cursorWatch);
      window->callbacksInInteractiveMode.action(&ev, window->currentData);
      gdk_window_set_cursor(GDK_WINDOW(window->socketOpenGL->window),
			window->currentCursor);
    }

  return TRUE;
}
static gboolean onKeyPressed(GtkWidget *widget, GdkEventKey *event, gpointer user_data)
{
  SimplifiedEvents ev;
  RenderingWindow *window;

  window = RENDERING_WINDOW(user_data);
  g_return_val_if_fail(window, TRUE);

  ev.button = 0;
  ev.motion = 0;
  ev.letter = '\0';

  gdk_window_set_cursor(GDK_WINDOW(window->socketOpenGL->window),
			RENDERING_WINDOW_CLASS(G_OBJECT_GET_CLASS(window))->cursorWatch);
  if(event->keyval == GDK_r || event->keyval == GDK_R)
    ev.letter = 'r';
  if(event->keyval == GDK_space)
    ev.letter = ' ';

  window->callbacksInInteractiveMode.action(&ev, window->currentData);
  gdk_window_set_cursor(GDK_WINDOW(window->socketOpenGL->window),
			window->currentCursor);

  return TRUE;
}

void renderingWindowStop_defaultIneractiveMode(RenderingWindow *window)
{
  g_return_if_fail(IS_RENDERING_WINDOW(window));

  if (!window->interactiveModeIsActive)
    return;
  
  window->interactiveModeIsActive = FALSE;
  /* Stop and free the measurements of several nodes. */
  endPickMesure(window->pickMesure);
  /* Stop the observe mode */
  openGLInteractiveEnd_session();
  while (window->nbStatusMessage > 0)
    {
      window->nbStatusMessage -= 1;
      renderingWindowPop_message(window);
    }
}
void renderingWindowStart_defaultIneractiveMode(RenderingWindow *window)
{
  g_return_if_fail(IS_RENDERING_WINDOW(window));

  if (window->interactiveModeIsBlocked)
    return;

  if (window->interactiveModeIsActive)
    {
      /* Reset the statusbar informations. */
      while (window->nbStatusMessage > 0)
	{
	  window->nbStatusMessage -= 1;
	  renderingWindowPop_message(window);
	}
      /* Put a commentary in the statusbar. */
      renderingWindowPush_message(window,
				  _("Observe mode & right-clic and <shift> right-clic to pick."));
      window->nbStatusMessage += 1;
      return;
    }
  
  window->interactiveModeIsActive = TRUE;
  /* Create a pickMesure object to enable the storage of several
     nodes and the printing of marks. */
  window->pickMesure = initPickMesure(window->currentData, FALSE, FALSE);
  /* Enter in the observe mode as default. */
  openGLInteractiveInit_session(window, minimalPickInfo, window, (GDestroyNotify)0);
  openGLInteractiveBegin_pickAndObserve();
  /* Put a commentary in the statusbar. */
  renderingWindowPush_message(window,
			    _("Observe mode & right-clic and <shift> right-clic to pick."));
  window->nbStatusMessage += 1;
}
void renderingWindowBlock_defaultIneractiveMode(RenderingWindow *window)
{
  g_return_if_fail(IS_RENDERING_WINDOW(window));

  if (window->interactiveModeIsBlocked)
    return;
  renderingWindowStop_defaultIneractiveMode(window);
  window->interactiveModeIsBlocked = TRUE;
}
void renderingWindowUnblock_defaultIneractiveMode(RenderingWindow *window)
{
  g_return_if_fail(IS_RENDERING_WINDOW(window));

  window->interactiveModeIsBlocked = FALSE;
  renderingWindowStart_defaultIneractiveMode(window);
}

void renderingWindowPush_message(RenderingWindow *window, gchar *message)
{
  g_return_if_fail(IS_RENDERING_WINDOW(window));

  gtk_statusbar_push(GTK_STATUSBAR(window->info->statusInfo),
		     window->info->statusInfoId, message);
}
void renderingWindowPop_message(RenderingWindow *window)
{
  g_return_if_fail(IS_RENDERING_WINDOW(window));

  gtk_statusbar_pop(GTK_STATUSBAR(window->info->statusInfo),
		    window->info->statusInfoId);
}
void renderingWindowGet_openGLAreaSize(RenderingWindow *window,
				       unsigned int *width, unsigned int *height)
{
  g_return_if_fail(IS_RENDERING_WINDOW(window) && width && height);

  gdk_drawable_get_size(GDK_DRAWABLE(window->socketOpenGL->window),
			(gint*)width, (gint*)height);
}
GdkPixbuf* renderingWindowGet_backgroundImage(RenderingWindow *window,
					     guchar **rowData, gboolean *hasAlphaChannel,
					     int *width, int *height)
{
  g_return_val_if_fail(IS_RENDERING_WINDOW(window), (GdkPixbuf*)0);

  g_return_val_if_fail(rowData && hasAlphaChannel && width && height, (GdkPixbuf*)0);

  if (!window->backLogo)
    window->backLogo = create_pixbuf("logo_grey.png");
  g_return_val_if_fail(window->backLogo, (GdkPixbuf*)0);

  *rowData = gdk_pixbuf_get_pixels(window->backLogo);
  *hasAlphaChannel = gdk_pixbuf_get_has_alpha(window->backLogo);
  *width = gdk_pixbuf_get_width(window->backLogo);
  *height = gdk_pixbuf_get_height(window->backLogo);
  g_object_ref(G_OBJECT(window->backLogo));
  return window->backLogo;
}
void renderingWindowFree_backgroundImage(RenderingWindow *window)
{
  g_return_if_fail(IS_RENDERING_WINDOW(window));

  if (window->backLogo)
    g_object_unref(G_OBJECT(window->backLogo));
  window->backLogo = (GdkPixbuf*)0;
}
void renderingWindowSet_visuData(RenderingWindow *window, VisuData* data)
{
  gboolean noEmit;
  gchar *nom, *file;
  guint w, h;

  g_return_if_fail(IS_RENDERING_WINDOW(window));

  DBG_fprintf(stderr, "Gtk renderingWindow : attach %p VisuData to %p window.\n",
	      (gpointer)data, (gpointer)window);
  noEmit = (!window->currentData && !data);
  if (window->currentData != data)
    {
      if (window->currentData)
	{
	  visuDataSet_renderingWindow(window->currentData, (GenericRenderingWindow)0);
	  g_object_unref(window->currentData);
	}
      window->currentData = data;
    }

  if (data)
    {
      /* Set the window as attachingRenderingWindow for the given VisuData. */
      visuDataSet_renderingWindow(data, (GenericRenderingWindow)window);
      renderingWindowGet_openGLAreaSize(window, &w, &h);
      visuDataSet_sizeOfView(data, w, h);
      /* Change the name of the window, according to the file loaded. */
      nom = visuDataGet_file(data, 0);
      if (nom)
	file = g_path_get_basename(nom);
      else
	{
	  g_warning("Can't find the filename to label the rendering window.\n");
	  file = g_strdup(_("No filename"));
	}
      gtk_window_set_title(GTK_WINDOW(window), file);
      g_free(file);
      /* Start an observe session. */
      renderingWindowStart_defaultIneractiveMode(window);
    }
  else
    {
      /* Erase the name of the window. */
      gtk_window_set_title(GTK_WINDOW(window), _("No file loaded"));
      /* Stop the observe session. */
      renderingWindowStop_defaultIneractiveMode(window);
    }
  displayFileInfoOnDataLoaded(window);
  setDumpButtonSensitive(window);

  if (!noEmit)
    {
      DBG_fprintf(stderr, "Gtk renderingWindow : emitting the 'dataReadyForRendering' signal.\n");
      g_signal_emit(visu, VISU_GET_CLASS (visu)->dataReadyForRendering_signal_id,
		    0 /* details */, (gpointer)data, NULL);
      DBG_fprintf(stderr, "Gtk renderingWindow : emitting done.\n");
    }
}
VisuData* renderingWindowGet_visuData(RenderingWindow *window)
{
  g_return_val_if_fail(IS_RENDERING_WINDOW(window), (VisuData*)0);
  return window->currentData;
}

/***************************/
/* GtkStatusInfo functions */
/***************************/
void gtkStatusInfo_showSizeWarning(GtkInfoArea *info, gboolean bool)
{
  g_return_if_fail(info);

  if (info->fileInfoFreeze)
    return;

  if (bool)
    gtk_widget_show(info->eventsWarningSize);
  else
    gtk_widget_hide(info->eventsWarningSize);
}
void gtkStatusInfo_setOpenGLSize(GtkInfoArea *info, gint width, gint height, gboolean bool)
{
  GString *str;

  g_return_if_fail(info);

  if (info->fileInfoFreeze)
    return;

  if (bool)
    str = g_string_new("<span size=\"smaller\" color=\"red\">");
  else
    str = g_string_new("<span size=\"smaller\">");
  g_string_append_printf(str, _("<b>Size:</b> %dx%d"), width, height);
  g_string_append_printf(str, "</span>");
  gtk_label_set_markup(GTK_LABEL(info->labelSize), str->str);
  g_string_free(str, TRUE);
}
void gtkStatusInfo_setFileDescription(GtkInfoArea *info, gchar* message)
{
  GString *str;

  g_return_if_fail(info);

  str = g_string_new("<span size=\"smaller\">");
  g_string_append_printf(str, _("<b>File info:</b> %s"), message);
  g_string_append_printf(str, "</span>");
  gtk_label_set_markup(GTK_LABEL(info->labelFileInfo), str->str);
  g_string_free(str, TRUE);
}
void gtkStatusInfo_setNbNodes(GtkInfoArea *info, gint nb)
{
  GString *str;

  g_return_if_fail(info);

  str = g_string_new("<span size=\"smaller\">");
  if (nb > 0)
    g_string_append_printf(str, _("<b>Nb nodes:</b> %d"), nb);
  else
    g_string_append(str, GTK_STATUSINFO_NONB);
  g_string_append_printf(str, "</span>");
  gtk_label_set_markup(GTK_LABEL(info->labelNb), str->str);
  g_string_free(str, TRUE);
}
void onFileInfoToggled(GtkToggleButton *button, gpointer data)
{
  unsigned int w, h;
  RenderingWindow *window;

  window = RENDERING_WINDOW(data);
  g_return_if_fail(window);

  window->info->fileInfoFreeze = TRUE;

  if (gtk_toggle_button_get_active(button))
    gtk_widget_show(GTK_WIDGET(window->info->hboxFileInfo));
  else
    gtk_widget_hide(GTK_WIDGET(window->info->hboxFileInfo));

  while(gtk_events_pending())
    gtk_main_iteration();

  renderingWindowGet_openGLAreaSize(window, &w, &h);
  if (window->currentData)
    visuDataSet_sizeOfView(window->currentData, w, h);
  else
    OpenGLViewSet_windowSize((OpenGLView*)0, w, h);

  if (gtk_toggle_button_get_active(button))
    window->info->fileInfoFreeze = FALSE;

  gtkStatusInfo_showSizeWarning(window->info, FALSE);
  gtkStatusInfo_setOpenGLSize(window->info, w, h, FALSE);

  g_signal_emit(visu, VISU_GET_CLASS(visu)->OpenGLForceReDraw_signal_id,
		0 , NULL);
}

void displayFileInfoOnDataLoaded(RenderingWindow *window)
{
  gchar* message;

  g_return_if_fail(window);

  if (window->currentData)
    {
      message = visuDataGet_fileCommentary((VisuData*)window->currentData);
      gtkStatusInfo_setNbNodes(window->info,
			       ((VisuData*)window->currentData)->nbOfAllStoredNodes);
    }
  else
    {
      message = (gchar*)0;
      gtkStatusInfo_setNbNodes(window->info, -1);
    }
  if (message)
    gtkStatusInfo_setFileDescription(window->info, message);
  else
    gtkStatusInfo_setFileDescription(window->info,
				     GTK_STATUSINFO_NOFILEINFO);
}

void renderingWindowLoad_file(RenderingWindow *window)
{
  onLoadFileClicked(window, (gpointer)0);
}

void onLoadFileClicked(RenderingWindow *window, gpointer data)
{
  GtkFileChooser *fileChooser;
  GtkWidget *dialog;
  int res;
  createGtkLoadWidgetFunc loadAction;
  gchar *directory;
  RenderingMethod* method;
  VisuData *newData;
  OpenGLView *view;

  method = getRenderingMethodInUse();
  g_return_if_fail(method);

  loadAction = gtkMainGet_renderingSpecificOpen(method);
  g_return_if_fail(loadAction);

  if (window->currentData)
    newData = visuDataNew_withOpenGLView(visuDataGet_openGLView(window->currentData));
  else
    newData = visuDataNew();
  g_return_if_fail(newData);

  res = loadAction(newData, &fileChooser, &dialog);
  
  directory = gtk_file_chooser_get_current_folder(fileChooser);
  setLastOpenDirectory((char*)directory);
  g_free(directory);

  if (res)
    {
      gtk_widget_destroy(dialog);
      visuWaitFunction();
      g_idle_add(loadAndRenderFileWithGtk, (gpointer)newData);
    }
  else
    {
      gtk_widget_destroy(dialog);
      g_object_unref(newData);
    }
}

void onRefreshViewClicked(GtkButton *button, gpointer data)
{
  g_idle_add(updateOpenGLAreaSize, (gpointer)data);
}

void onRenderingMethodChanged(RenderingWindow *window, gpointer data)
{
  /* First free attached visuData. */
  renderingWindowSet_visuData(window, (VisuData*)0);

  /* Customize interface according to new method. */
  if (getRenderingMethodInUse())
    {
      renderingWindowPop_message(window);
      gtk_widget_set_sensitive(window->info->loadButton, TRUE);
      renderingWindowPush_message(window, _("Use the 'open' button to render a file."));
    }
  else
    {
      gtk_widget_set_sensitive(window->info->loadButton, FALSE);
      renderingWindowPop_message(window);
    }
}

void setDumpButtonSensitive(RenderingWindow *window)
{
  g_return_if_fail(window);

  if (window->currentData)
    gtk_widget_set_sensitive(window->info->dumpButton, TRUE);
  else
    gtk_widget_set_sensitive(window->info->dumpButton, FALSE);
}

void updateDumpProgressBar(gpointer data)
{
  gdouble val;

  g_return_if_fail(GTK_PROGRESS_BAR(data));

  gtk_progress_bar_set_text(GTK_PROGRESS_BAR(data), _("Saving image..."));
  val = gtk_progress_bar_get_fraction(GTK_PROGRESS_BAR(data));
  if (val + 0.01 <= 1.0 && val >= 0.)
    gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(data), val + 0.01);
  visuWaitFunction();
}

static void onDumpButtonClicked(GtkButton *button, gpointer user_data)
{
  GtkWidget *dump;
  char *filename;
  DumpType *format;
  int res;
  GString *buffer;
  GdkCursor *cursorWatch;
  GtkProgressBar *dumpBar;

  dump = dumpDialog_new(RENDERING_WINDOW(user_data)->currentData);
  if (gtk_dialog_run(GTK_DIALOG(dump)) != GTK_RESPONSE_ACCEPT)
    {
      gtk_widget_destroy(dump);
      return;
    }

  filename = dumpDialogGet_fileName(DUMP_DIALOG(dump));
  format = dumpDialogGet_dumpType(DUMP_DIALOG(dump));

  if (!format || !filename)
    {
      fprintf(stderr, "INTERNAL ERROR! The dump dialog doesn't"
	      " return the desired format nor the chosen name.\n");
      exit(1);
    }
  DBG_fprintf(stderr, "Gtk StatusInfo : dump image to the file '%s' (format : %s)\n",
	      filename, format->fileType->description);
  if (format->writeFunc)
    {
      cursorWatch = gdk_cursor_new(GDK_WATCH);
      dumpBar = dumpDialogGet_progressBar(DUMP_DIALOG(dump));
      gtk_progress_bar_set_fraction(dumpBar, 0.);
      buffer = g_string_new(_("Dumping the view to image file"));
      g_string_append_printf(buffer, _(" (format '%s').\n"), format->fileType->description);
      g_string_append_printf(buffer, _("Write to '%s'.\n\n"), filename);
      gtk_progress_bar_set_text(dumpBar,
				_("Waiting for generating image in memory..."));
      visuWaitFunction();
      gdk_window_set_cursor(GDK_WINDOW((GTK_WIDGET(dump))->window), cursorWatch);
      res = format->writeFunc(format->fileType, buffer, filename,
			      dumpDialogGet_widthValue(DUMP_DIALOG(dump)),
			      dumpDialogGet_heightValue(DUMP_DIALOG(dump)),
			      RENDERING_WINDOW(user_data)->currentData,
			      updateDumpProgressBar, (gpointer)dumpBar);
      gdk_window_set_cursor(GDK_WINDOW((GTK_WIDGET(dump))->window), NULL);
      if (res)
	raiseAlertDialog(buffer->str);
      g_string_free(buffer, TRUE);
    }
  gtk_widget_destroy(dump);
}
gboolean renderingWindowSet_context(RenderingWindow *window, gboolean newContext)
{
  int res;
#if SYSTEM_X11 == 1
  XID XWindowId;
#endif
#if SYSTEM_WIN32 == 1
  HANDLE windowHandler;
  GdkDrawable *impl;
#endif

  g_return_val_if_fail(IS_RENDERING_WINDOW(window), FALSE);

#if SYSTEM_X11 == 1
  XWindowId = gdk_x11_drawable_get_xid(GDK_DRAWABLE(window->socketOpenGL->window));
  DBG_fprintf(stderr, "Gtk RenderingWindow : attach direct context"
	      " to this window (%d).\n", (int)XWindowId);
  if (newContext)
    {
      setDisplay((gpointer)gdk_x11_drawable_get_xdisplay(GDK_DRAWABLE(window->socketOpenGL->window)));
      setScreen(gdk_x11_screen_get_screen_number(gdk_drawable_get_screen(GDK_DRAWABLE(window->socketOpenGL->window))));
      initOpenGLContext();
    }
  res = attachOpenGlContext(FALSE, (gpointer)&XWindowId);
#endif
#if SYSTEM_WIN32 == 1
  if (newContext)
    g_warning("Creating a new context is not implemented under Win32 platform.");
  impl = ((GdkWindowObject*)window->socketOpenGL->window)->impl;
  windowHandler = ((GdkDrawableImplWin32*)impl)->handle;
  DBG_fprintf(stderr, "Gtk RenderingWindow : attach direct context"
	      " to this window (%d).\n", (int)windowHandler);
  res = attachOpenGlContext(FALSE, (gpointer)&windowHandler);
#endif

  openGLInit_context();

  return res;
}
