/*   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-2005)

     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.
*/

#include <gtk/gtk.h>
#include <gdk/gdkkeysyms.h>
#include <glib.h>
#include <locale.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h> /* For the access markers R_OK, W_OK ... */
#include <sys/stat.h>
#include <sys/types.h>

#include "interface.h"
#include "support.h"
#include "gtk_main.h"
#include "gtk_interactive.h"
#include "gtk_pick.h"
#include "gtk_move.h"
#include "gtk_pairs.h"
#include "gtk_about.h"
#include "gtk_save.h"
#include "gtk_renderingWindowWidget.h"
#include "extraGtkFunctions/gtk_colorComboBoxWidget.h"
#include "extraGtkFunctions/gtk_shadeComboBoxWidget.h"
#include "extraGtkFunctions/gtk_fieldChooser.h"
#include "extraGtkFunctions/gtk_dataChooser.h"

#include "panelModules/externalModules.h"
#include "panelModules/panelElements.h"
#include "panelModules/panelAxes.h"
#include "panelModules/panelBrowser.h"
#include "panelModules/panelDataFile.h"
#include "panelModules/panelPlanes.h"

#include "visu_gtk.h"
#include "opengl.h"
#include "visu_data.h"
#include "visu_dataatomic.h"
#include "visu_configFile.h"
#include "visu_basic.h"            /* To have loadDataFromFile */
#include "visu_commandLine.h"      /* To have getArgFilename and getXWindowGeometry*/
#include "visu_extension.h"
#include "visu_plugins.h"
#include "coreTools/toolOptions.h"
#include "coreTools/toolConfigFile.h"
#include "extraFunctions/dataFile.h"
#include "extraFunctions/scalarFieldSet.h"
#include "extensions/pairs.h"
#include "extensions/surfs.h"
#include "extensions/geodiff.h"
#include "extensions/mapset.h"

/**
 * SECTION: gtk_main
 * @short_description: The command panel definition.
 *
 * <para>This is the main interface in V_Sim. It hosts the common action
 * buttons, like open a file, save resources, switch to interactive
 * session... It also hosts the different panels.</para>
 */

/**
 * VisuUiMain:
 *
 * Structure to describe the main interface of V_Sim.
 */

enum {
  DATA_FOCUSED_SIGNAL,
  DIR_SIGNAL,
  LAST_SIGNAL
};

static guint visu_ui_main_signals[LAST_SIGNAL];

struct _VisuUiMainClass
{
  GtkWindowClass parent;

  /* Gestion of the main window positioning. */
  gboolean rememberWindowPosition;
  GHashTable *windowPosition;

  /* Alert or not when quiting. */
  gboolean warningWhenQuit;
};

/**
 * VisuUiMainPrivate:
 *
 * Private fields of a #VisuUiMain object.
 */
struct _VisuUiMainPrivate
{
  gboolean dispose_has_run;

  /* Pointers on different inside widgets. */
  GtkWidget *loadButton;
  GtkWidget *checkPairs;
  GtkWidget *pairsButton;
  GtkWidget *mouseActions;
  GtkWidget *saveButton;
  GtkWidget *quitButton;
  GtkWidget *aboutButton;
  GtkWidget *vboxMain;

  /* Variables. */
  gboolean oneWindow;
  gboolean actionDialogIsShown;

  /* Store the last open directory. It is initialised
     to current working directory. */
  gchar *lastDir;
};

/* Local object method. */
static void visu_ui_main_class_init(VisuUiMainClass *klass);
static void visu_ui_main_init      (VisuUiMain *obj);
static void visu_ui_main_dispose   (GObject *obj);
static void visu_ui_main_finalize  (GObject *obj);

/* Local variables. */
static GtkWindowClass *parent_class  = NULL;
static VisuUiMainClass   *my_class   = NULL;
static VisuUiMain *currentVisuUiMain = NULL;
static gint gtkFileChooserWidth = -1, gtkFileChooserHeight = -1;

/* Miscelaneous functions with gtk */
static void hideWindow(GtkWindow *win);
static void showWindow(GtkWindow *win);


/* Local callbacks */
static gboolean onHomePressed(GtkWidget *widget _U_, GdkEventKey *event,
			      gpointer data);
static void onLoadButtonClicked(VisuUiMain *main, GtkButton *button);
static void onPairsButtonClicked(VisuUiMain *main, GtkButton *button);
static void onMouseActionsClicked(VisuUiMain *main, GtkButton *button);
static void onSaveButtonClicked(VisuUiMain *main, GtkButton *button);
static void onQuitButtonClicked(VisuUiMain *main, GtkButton *button);
static void onAboutButtonClicked(VisuUiMain *main, GtkButton *button);
static void onDataReady(VisuGlNodeScene *scene, GParamSpec *pspec, gpointer data);
static void onShowActionDialog(VisuUiMain *main, VisuUiRenderingWindow *window);
static void onShowMainPanel(VisuUiMain *main, VisuUiRenderingWindow *window);
static gboolean onKillPairsDialog(VisuUiMain *main, GdkEvent *event, gpointer data);
static gboolean onKillAboutDialog(VisuUiMain *main, GdkEvent *event, gpointer data);
static gboolean onKillInteractiveDialog(VisuUiMain *main, GdkEvent *event,
					gpointer data);
static gboolean onKillMainWindowEvent(GtkWidget *widget, GdkEvent *event,
				      gpointer user_data);

void onHideNextTime(GtkToggleButton *button, gpointer data);

/* Parameter to store the position of windows. */
#define PARAMETER_GTKMAIN_REMEMBER_DEFAULT TRUE

/* Parameter to change the policy of the warning quit dialog. */
#define FLAG_PARAMETER_GTKMAIN_QUIT    "main_confirmQuit"
#define DESC_PARAMETER_GTKMAIN_QUIT    "Show up a dialog to confirm when quit button is clicked ; boolean 0 or 1"
#define PARAMETER_GTKMAIN_QUIT_DEFAULT TRUE

#define FLAG_PARAMETER_GTKMAIN_PANEL   "main_panelStatus"
#define DESC_PARAMETER_GTKMAIN_PANEL   "Attach a panel to a tool window ; panel_name window_name (or None or Main)"
static gboolean readMainPanelStatus(VisuConfigFileEntry *entry _U_, gchar **lines, int nbLines, int position,
				    GError **error);
#define FLAG_PARAMETER_GTKMAIN_DOCK   "main_dock"
#define DESC_PARAMETER_GTKMAIN_DOCK   "Define the characteristic of a dock window ; visibility size(x,y) position(w,h) window_name"
static gboolean readMainDock(VisuConfigFileEntry *entry _U_, gchar **lines, int nbLines, int position,
			     GError **error);
static void exportParametersVisuUiMain(GString *data,
                                       VisuData *dataObj);


/* Number of time V_Sim try to attach the OpenGL context. */
#define VISU_UI_MAIN_N_MAX_OPENGL 10

/*******************/
/* Object methods. */
/*******************/
G_DEFINE_TYPE_WITH_CODE(VisuUiMain, visu_ui_main, GTK_TYPE_WINDOW,
                        G_ADD_PRIVATE(VisuUiMain))

static void visu_ui_main_class_init(VisuUiMainClass *klass)
{
  VisuConfigFileEntry *resourceEntry;

  DBG_fprintf(stderr, "Gtk Main: creating the class of the object.\n");

  parent_class = g_type_class_peek_parent(klass);
  my_class     = klass;

  /**
   * VisuUiMain::DataFocused:
   * @ui: the object which received the signal ;
   * @dataObj: the newly associated #VisuData object.
   *
   * This signal is emitted when @dataObj has been displayed on the
   * rendering window and is ready for use.
   *
   * Since: 3.7
   */
  visu_ui_main_signals[DATA_FOCUSED_SIGNAL] =
    g_signal_new("DataFocused", G_TYPE_FROM_CLASS(klass),
                 G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
                 0 , NULL, NULL, g_cclosure_marshal_VOID__OBJECT,
                 G_TYPE_NONE, 1, VISU_TYPE_DATA);
  /**
   * VisuUiMain::DirectoryChanged:
   * @ui: the object emitting the signal.
   * @kind: a flag.
   *
   * The current directory has been changed. The kind of directory is
   * defined by @kind (see #).
   *
   * Since: 3.6
   */
  visu_ui_main_signals[DIR_SIGNAL] = 
    g_signal_new("DirectoryChanged", G_TYPE_FROM_CLASS (klass),
                 G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
                 0, NULL, NULL, g_cclosure_marshal_VOID__UINT,
                 G_TYPE_NONE, 1, G_TYPE_UINT);

  /* Connect freeing methods. */
  G_OBJECT_CLASS(klass)->dispose  = visu_ui_main_dispose;
  G_OBJECT_CLASS(klass)->finalize = visu_ui_main_finalize;

  /* Add the config file entries. */
  visu_config_file_addKnownTag("gtk");

  DBG_fprintf(stderr, "                - add config file entries ;\n");
  resourceEntry = visu_config_file_addBooleanEntry(VISU_CONFIG_FILE_PARAMETER,
                                                   FLAG_PARAMETER_GTKMAIN_QUIT,
                                                   DESC_PARAMETER_GTKMAIN_QUIT,
                                                   &klass->warningWhenQuit, FALSE);
  visu_config_file_entry_setVersion(resourceEntry, 3.3f);
  resourceEntry = visu_config_file_addEntry(VISU_CONFIG_FILE_PARAMETER,
					  FLAG_PARAMETER_GTKMAIN_PANEL,
					  DESC_PARAMETER_GTKMAIN_PANEL,
					  1, readMainPanelStatus);
  visu_config_file_entry_setVersion(resourceEntry, 3.3f);
  resourceEntry = visu_config_file_addEntry(VISU_CONFIG_FILE_PARAMETER,
					  FLAG_PARAMETER_GTKMAIN_DOCK,
					  DESC_PARAMETER_GTKMAIN_DOCK,
					  1, readMainDock);
  visu_config_file_entry_setVersion(resourceEntry, 3.3f);
  visu_config_file_addExportFunction(VISU_CONFIG_FILE_PARAMETER,
				   exportParametersVisuUiMain);

  /* Set static parameters. */
  DBG_fprintf(stderr, "                - miscelaneous ;\n");
  klass->rememberWindowPosition = PARAMETER_GTKMAIN_REMEMBER_DEFAULT;
  klass->warningWhenQuit        = PARAMETER_GTKMAIN_QUIT_DEFAULT;
  klass->windowPosition = g_hash_table_new_full(g_direct_hash,
						g_direct_equal,
						NULL, g_free);

  /* Force the creation of the VisuUiColorComboboxClass. */
  g_type_class_ref(visu_ui_color_combobox_get_type());
  g_type_class_ref(VISU_TYPE_UI_DATA_CHOOSER);
  g_type_class_ref(VISU_TYPE_UI_FIELD_CHOOSER);
  g_type_class_ref(VISU_TYPE_UI_PANEL);
}

static void _buildWidgets(VisuUiMain *obj, gboolean oneWindow)
{
  int width, height;
  int i;
  GtkWidget *vbox, *hbox, *hbox2, *wd, *image, *label, *pane;
  VisuUiPanel *panel;
  VisuUiDockWindow *dockMain;
  VisuGlNodeScene *scene;
#if GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION < 12
  GtkTooltips *tooltips;
  tooltips = gtk_tooltips_new ();
#endif

  currentVisuUiMain = obj;

  /* Private data. */
  DBG_fprintf(stderr, "--- Initialising the GTK interface ---\n");
  DBG_fprintf(stderr, " | Gtk Main");

  gtk_window_set_title(GTK_WINDOW(obj), _("Command panel"));
#if GTK_MAJOR_VERSION < 3 || (GTK_MAJOR_VERSION == 3 && GTK_MINOR_VERSION < 22)
  gtk_window_set_wmclass(GTK_WINDOW(obj), "v_sim_commandPanel", "V_Sim");
#else
  gtk_window_set_role(GTK_WINDOW(obj), "v_sim_commandPanel");
#endif

  obj->priv->vboxMain = gtk_vbox_new(FALSE, 0);
  gtk_widget_set_size_request(obj->priv->vboxMain, 350, -1);
  gtk_container_set_border_width(GTK_CONTAINER(obj->priv->vboxMain), 7);

  obj->priv->oneWindow = oneWindow;

  DBG_fprintf(stderr,"--- Initialising the rendering window ---\n");
  commandLineGet_XWindowGeometry(&width, &height);
  obj->renderingWindow = visu_ui_rendering_window_new(width, height,
                                                      obj->priv->oneWindow, TRUE);
  g_signal_connect_swapped(G_OBJECT(obj->renderingWindow), "show-action-dialog",
                           G_CALLBACK(onShowActionDialog), (gpointer)obj);
  g_signal_connect_swapped(G_OBJECT(obj->renderingWindow), "show-main-panel",
                           G_CALLBACK(onShowMainPanel), (gpointer)obj);

  if (oneWindow)
    {
      pane = gtk_hpaned_new();
      gtk_container_add(GTK_CONTAINER(obj), pane);
      gtk_widget_show(pane);
      gtk_paned_pack1(GTK_PANED(pane), obj->priv->vboxMain, FALSE, FALSE);
      gtk_paned_pack2(GTK_PANED(pane), obj->renderingWindow, TRUE, TRUE);
    }
  else
    gtk_container_add(GTK_CONTAINER(obj), obj->priv->vboxMain);

  scene = visu_ui_rendering_window_getGlScene(VISU_UI_RENDERING_WINDOW(obj->renderingWindow));

  wd = gtk_frame_new(_("Actions"));
  gtk_box_pack_end(GTK_BOX(obj->priv->vboxMain), wd, FALSE, FALSE, 0);

  vbox = gtk_vbox_new(FALSE, 0);
  gtk_container_add(GTK_CONTAINER(wd), vbox);

  hbox = gtk_hbox_new(FALSE, 0);
  gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
  gtk_container_set_border_width(GTK_CONTAINER(hbox), 5);

  obj->priv->loadButton = gtk_button_new_from_icon_name("document-open",
                                                           GTK_ICON_SIZE_BUTTON);
  gtk_box_pack_start(GTK_BOX(hbox), obj->priv->loadButton, TRUE, TRUE, 0);
  gtk_widget_set_tooltip_text(obj->priv->loadButton,
			      _("Select a file to render."));

  hbox2 = gtk_hbox_new(FALSE, 0);
  gtk_box_pack_start(GTK_BOX(hbox), hbox2, TRUE, TRUE, 10);

  obj->priv->checkPairs = gtk_check_button_new();
  g_object_bind_property(visu_gl_node_scene_getPairs(scene), "active",
                         obj->priv->checkPairs, "active",
                         G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE);
  gtk_box_pack_start(GTK_BOX(hbox2), obj->priv->checkPairs, FALSE, FALSE, 0);
  gtk_widget_set_tooltip_text(obj->priv->checkPairs,
			      _("Check to draw pairs between elements."));

  obj->priv->pairsButton = gtk_button_new();
  g_object_bind_property(obj->renderingWindow, "data", obj->priv->pairsButton,
                         "sensitive", G_BINDING_SYNC_CREATE);
  gtk_box_pack_start(GTK_BOX(hbox2), obj->priv->pairsButton, TRUE, TRUE, 0);
  gtk_widget_set_tooltip_text(obj->priv->pairsButton,
			      _("Configure parameters for bindings such as color, thickness..."));

  wd = gtk_hbox_new(FALSE, 2);
  gtk_container_add(GTK_CONTAINER(obj->priv->pairsButton), wd);

  image = gtk_image_new_from_icon_name("emblem-shared", GTK_ICON_SIZE_BUTTON);
  gtk_box_pack_start(GTK_BOX(wd), image, FALSE, FALSE, 0);

  label = gtk_label_new_with_mnemonic(_("_Pairs"));
  gtk_box_pack_start(GTK_BOX(wd), label, FALSE, FALSE, 0);

  obj->priv->mouseActions = gtk_button_new();
  g_object_bind_property(obj->renderingWindow, "data", obj->priv->mouseActions,
                         "sensitive", G_BINDING_SYNC_CREATE);
  gtk_box_pack_start(GTK_BOX(hbox), obj->priv->mouseActions, TRUE, TRUE, 0);
  gtk_widget_set_tooltip_text(obj->priv->mouseActions,
			      _("Use the mouse to change the view and get position informations."));

  wd = gtk_hbox_new(FALSE, 2);
  gtk_container_add(GTK_CONTAINER(obj->priv->mouseActions), wd);

  image = gtk_image_new_from_icon_name("zoom-fit-best", GTK_ICON_SIZE_BUTTON);
  gtk_box_pack_start(GTK_BOX(wd), image, FALSE, FALSE, 0);

  label = gtk_label_new_with_mnemonic(_("Mouse _actions"));
  gtk_box_pack_start(GTK_BOX(wd), label, FALSE, FALSE, 0);

  hbox = gtk_hbox_new(FALSE, 5);
  gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
  gtk_container_set_border_width(GTK_CONTAINER(hbox), 5);

  obj->priv->saveButton = gtk_button_new();
  gtk_box_pack_start(GTK_BOX(hbox), obj->priv->saveButton, TRUE, TRUE, 5);
  gtk_widget_set_tooltip_text(obj->priv->saveButton,
			      _("Click to save the parameters or the resources."));

  wd = gtk_hbox_new(FALSE, 2);
  gtk_container_add(GTK_CONTAINER(obj->priv->saveButton), wd);

  image = gtk_image_new_from_icon_name("document-save", GTK_ICON_SIZE_BUTTON);
  gtk_box_pack_start(GTK_BOX(wd), image, FALSE, FALSE, 0);

  label = gtk_label_new_with_mnemonic(_("_Config. files"));
  gtk_box_pack_start(GTK_BOX(wd), label, FALSE, FALSE, 0);

  obj->priv->quitButton = gtk_button_new_from_icon_name("application-exit",
                                                           GTK_ICON_SIZE_BUTTON);
  gtk_box_pack_start(GTK_BOX(hbox), obj->priv->quitButton, TRUE, TRUE, 5);

  obj->priv->aboutButton = gtk_button_new();
  gtk_box_pack_start(GTK_BOX(hbox), obj->priv->aboutButton, FALSE, FALSE, 15);
  gtk_widget_set_tooltip_text(obj->priv->aboutButton,
			      _("V_Sim program. Written by L. Billard, modified by D. Caliste."));
  gtk_button_set_relief(GTK_BUTTON(obj->priv->aboutButton), GTK_RELIEF_NONE);

  image = create_pixmap(GTK_WIDGET(obj), "logo_petit.png");
  gtk_container_add(GTK_CONTAINER(obj->priv->aboutButton), image);

  g_signal_connect_swapped(G_OBJECT(obj->priv->loadButton), "clicked",
			   G_CALLBACK(onLoadButtonClicked), (gpointer)obj);
  g_signal_connect_swapped(G_OBJECT(obj->priv->pairsButton), "clicked",
			   G_CALLBACK(onPairsButtonClicked), (gpointer)obj);
  g_signal_connect_swapped(G_OBJECT(obj->priv->mouseActions), "clicked",
			   G_CALLBACK(onMouseActionsClicked), (gpointer)obj);
  g_signal_connect_swapped(G_OBJECT(obj->priv->saveButton), "clicked",
			   G_CALLBACK(onSaveButtonClicked), (gpointer)obj);
  g_signal_connect_swapped(G_OBJECT(obj->priv->quitButton), "clicked",
			   G_CALLBACK(onQuitButtonClicked), (gpointer)obj);
  g_signal_connect_swapped(G_OBJECT(obj->priv->aboutButton), "clicked",
			   G_CALLBACK(onAboutButtonClicked), (gpointer)obj);
  g_signal_connect(G_OBJECT(obj), "delete-event",
		   G_CALLBACK(onKillMainWindowEvent), (gpointer)obj);
  g_signal_connect(G_OBJECT(obj), "destroy-event",
		   G_CALLBACK(onKillMainWindowEvent), (gpointer)obj);
  g_signal_connect_object(scene, "notify::data", 
                          G_CALLBACK(onDataReady), obj, G_CONNECT_AFTER);
  DBG_fprintf(stderr, " ... OK.\n");

  /* init the sub panel contains. */
  dockMain = visu_ui_panel_class_getCommandPanel();
  wd = visu_ui_dock_window_getContainer(dockMain);
  gtk_box_pack_start(GTK_BOX(obj->priv->vboxMain), wd, TRUE, TRUE, 0);

  /* Show all. */
  gtk_widget_show_all(obj->priv->vboxMain);

#define ADD(P) visu_ui_panel_attach(VISU_UI_PANEL(P), dockMain)
  ADD(visu_ui_panel_elements_init(obj));
  ADD(visu_ui_panel_axes_init(obj));
  for (i = 0; panelListAll[i]; i++)
    {
      panel = panelListAll[i](obj);
      if (!panel)
	{
	  g_error("Can't initialise subpanel number %d.\n", i);
	}

      visu_ui_panel_attach(panel, dockMain);
      if (i == 0)
	gtk_notebook_set_current_page(GTK_NOTEBOOK(visu_ui_dock_window_getNotebook(dockMain)), 0);
      
      DBG_fprintf(stderr, "Gtk Main: initialise '%s' subpanel OK.\n",
		  visu_ui_panel_getLabel(panel));
    }
  gtk_notebook_set_current_page(GTK_NOTEBOOK(visu_ui_dock_window_getNotebook(dockMain)), 0);
  DBG_fprintf(stderr, "Gtk Main: build widgets OK.\n");
}

static void visu_ui_main_init(VisuUiMain *obj)
{
  DBG_fprintf(stderr, "Gtk Main: initializing a new object (%p).\n",
	      (gpointer)obj);

  obj->priv = visu_ui_main_get_instance_private(obj);
  obj->priv->dispose_has_run = FALSE;

  /* Public data. */
  obj->renderingWindow    = (GtkWidget*)0;
  obj->pairsDialog        = (GtkWidget*)0;
  obj->interactiveDialog  = (GtkWidget*)0;
  obj->aboutDialog        = (GtkWidget*)0;

  /* Private variables. */
  obj->priv->oneWindow = FALSE;
  obj->priv->actionDialogIsShown = FALSE;

  /* Retrieve the current working directory. */
  obj->priv->lastDir = g_get_current_dir();

  g_signal_connect(G_OBJECT(obj), "key-press-event",
		   G_CALLBACK(onHomePressed), (gpointer)obj);

  /* Others elements linked to the main window. */
  DBG_fprintf(stderr, " | Gtk Interactive\n");
  visu_ui_interactive_init();
}

/* This method can be called several times.
   It should unref all of its reference to
   GObjects. */
static void visu_ui_main_dispose(GObject* obj)
{
  VisuUiMain *mainUI;

  DBG_fprintf(stderr, "Gtk Main: dispose object %p.\n", (gpointer)obj);

  mainUI = VISU_UI_MAIN(obj);

  if (mainUI->priv->dispose_has_run)
    return;
  mainUI->priv->dispose_has_run = TRUE;

  if (mainUI->renderingWindow && !mainUI->priv->oneWindow)
    {
      DBG_fprintf(stderr, "Gtk Main: destroying the rendering window.\n");
      gtk_widget_destroy(mainUI->renderingWindow);
    }

  DBG_fprintf(stderr, "Gtk Main: destroying the dialogs.\n");
  if (mainUI->pairsDialog)
    gtk_widget_destroy(mainUI->pairsDialog);

  if (mainUI->interactiveDialog)
    gtk_widget_destroy(mainUI->interactiveDialog);

  if (mainUI->aboutDialog)
    gtk_widget_destroy(mainUI->aboutDialog);

  /* Finish panels. */
  visu_ui_panel_axes_setAxesExtension((VisuGlExtAxes*)0);

  DBG_fprintf(stderr, "Gtk Main: chain to parent.\n");
  G_OBJECT_CLASS(parent_class)->dispose(obj);
  DBG_fprintf(stderr, "Gtk Main: dispose done.\n");
}
/* This method is called once only. */
static void visu_ui_main_finalize(GObject* obj)
{
  g_return_if_fail(obj);

  DBG_fprintf(stderr, "Gtk Main: finalize object %p.\n", (gpointer)obj);
  g_free(VISU_UI_MAIN(obj)->priv->lastDir);

  /* Chain up to the parent class */
  G_OBJECT_CLASS(parent_class)->finalize(obj);

  DBG_fprintf(stderr, "Gtk Main: freeing ... OK.\n");
}

GtkWidget* visu_ui_main_new(gboolean oneWindow)
{
  VisuUiMain *commandPanel;

  commandPanel = VISU_UI_MAIN(g_object_new(VISU_TYPE_UI_MAIN, NULL));
  if (!commandPanel)
    return (GtkWidget*)0;

  _buildWidgets(commandPanel, oneWindow);
  gtk_window_set_default_size(GTK_WINDOW(commandPanel), 100, -1);

  return GTK_WIDGET(commandPanel);
}
/**
 * visu_ui_main_getRendering:
 * @main: a #VisuUiMain object.
 *
 * Retrieve the rendering window controlled by @main.
 *
 * Since: 3.8
 *
 * Returns: (transfer none): the #VisuUiRenderingWindow controled by
 * this @main panel.
 **/
VisuUiRenderingWindow* visu_ui_main_getRendering(VisuUiMain *main)
{
  g_return_val_if_fail(VISU_IS_UI_MAIN(main), (VisuUiRenderingWindow*)0);
  return VISU_UI_RENDERING_WINDOW(main->renderingWindow);
}
/**
 * visu_ui_main_setLastOpenDirectory:
 * @main: a #VisuUiMain object.
 * @directory: a full path to a directory ;
 * @type: the kind of directory to set the remember flag on.
 *
 * V_Sim stores the last open directory to set the file chooser to
 * this one the next time it will come. Use this routine each time a
 * file chooser returns GTK_RESPONSE_OK. The given string will be
 * copied and can be freed after use.
 */
void visu_ui_main_setLastOpenDirectory(VisuUiMain *main,
                                       const char* directory, VisuUiDirectoryType type)
{
  g_return_if_fail(VISU_IS_UI_MAIN(main));

  g_free(main->priv->lastDir);

  if (!g_path_is_absolute(directory))
    main->priv->lastDir = g_build_filename(g_get_current_dir(), directory, NULL);
  else
    main->priv->lastDir = g_build_filename(directory, NULL);
  DBG_fprintf(stderr, "Visu Gtk: set the last open directory to '%s', emit signal.\n",
	      main->priv->lastDir);

  g_signal_emit(main, visu_ui_main_signals[DIR_SIGNAL], 0, type);
  DBG_fprintf(stderr, "Visu Gtk: emission done (DirectoryChanged).\n");
}
/**
 * visu_ui_main_getLastOpenDirectory:
 * @main: a #VisuUiMain object.
 *
 * V_Sim stores the last open directory to set the file chooser to
 * this one the next time it will come. Use
 * visu_ui_main_setLastOpenDirectory() to store it after a GTK_RESPONSE_OK
 * has been returned by a file chooser and then initialise each new
 * with this routine.
 *
 * Returns: (transfer none): a string owned by V_Sim.
 */
const char* visu_ui_main_getLastOpenDirectory(VisuUiMain *main)
{
  g_return_val_if_fail(VISU_IS_UI_MAIN(main), (gchar*)0);
  DBG_fprintf(stderr, "Visu Gtk: get the last open directory : '%s'.\n",
	      main->priv->lastDir);
  return main->priv->lastDir;
}
/**
 * visu_ui_main_getSelectedDirectory:
 * @main: a #VisuUiMain object.
 * @parent: (allow-none): if NULL, the command panel window is used ;
 * @multiple: if TRUE, multiple directories can be selected ;
 * @dir: (allow-none): if not NULL, give the opening directory.
 *
 * General procedure to get the location of one or more directories.
 * In the multiple case, all selected directories shares a common ancestor
 * since the selection is done through the same selector that for single
 * directory but with multiple selection activated. If @dir is NULL
 * the last opened (and stored) directory is used (see
 * visu_ui_main_getLastOpenDirectory() and visu_ui_main_setLastOpenDirectory()).
 *
 * Returns: (array zero-terminated=1) (transfer full): a newly
 * allocated array of paths, NULL terminated. Use g_strfreev() to free
 * it after use. If no directory is selected, then NULL is returned.
 */
gchar** visu_ui_main_getSelectedDirectory(VisuUiMain *main,
                                          GtkWindow *parent, gboolean multiple,
                                          const gchar *dir)
{
  GtkWidget *file_selector, *hbox, *wd;
  gchar **dirnames;
  GSList* names, *tmpLst;
  int i;

  /* Create the selector */
  if (!parent)
    parent = GTK_WINDOW(main);

  file_selector = gtk_file_chooser_dialog_new(_("Choose a directory"), parent,
					      GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER,
					      TOOL_ICON_CANCEL, GTK_RESPONSE_CANCEL,
					      TOOL_ICON_OPEN, GTK_RESPONSE_OK,
					      NULL);
  if (gtkFileChooserWidth > 0 || gtkFileChooserHeight > 0)
    gtk_window_set_default_size(GTK_WINDOW(file_selector), gtkFileChooserWidth,
				gtkFileChooserHeight);
  if (multiple)
    {
      hbox = gtk_hbox_new(FALSE, 0);
      gtk_file_chooser_set_extra_widget(GTK_FILE_CHOOSER(file_selector), hbox);
      wd = gtk_image_new_from_icon_name("help-browser", GTK_ICON_SIZE_MENU);
      gtk_box_pack_start(GTK_BOX(hbox), wd, FALSE, FALSE, 0);
      wd = gtk_label_new("");
      gtk_box_pack_start(GTK_BOX(hbox), wd, TRUE, TRUE, 5);
      gtk_label_set_xalign(GTK_LABEL(wd), 0.);
      gtk_label_set_use_markup(GTK_LABEL(wd), TRUE);
      gtk_label_set_markup(GTK_LABEL(wd), _("<span size=\"smaller\">Choose several"
					    " directories using the"
					    " <span font_desc=\"courier\">"
					    "Control</span> key.</span>"));
      gtk_widget_show_all(hbox);
    }
  if (!dir && visu_ui_main_getLastOpenDirectory(main))
    {
      DBG_fprintf(stderr, "Visu Gtk: open a directory chooser, set on '%s'.\n",
		  visu_ui_main_getLastOpenDirectory(main));
      gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(file_selector),
					  visu_ui_main_getLastOpenDirectory(main));
    }
  gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(file_selector), multiple);

  gtk_widget_set_name(file_selector, "filesel");
  gtk_window_set_position(GTK_WINDOW(file_selector), GTK_WIN_POS_CENTER_ON_PARENT);
  gtk_window_set_modal(GTK_WINDOW (file_selector), TRUE);

  if (gtk_dialog_run (GTK_DIALOG (file_selector)) == GTK_RESPONSE_OK)
    {
      names = gtk_file_chooser_get_filenames(GTK_FILE_CHOOSER(file_selector));
      dirnames = g_malloc(sizeof(gchar*) * (g_slist_length(names) + 1));
      tmpLst = names;
      i = 0;
      while(tmpLst)
	{
	  dirnames[i] = (gchar*)tmpLst->data;
	  i += 1;
	  tmpLst = g_slist_next(tmpLst);
	}
      dirnames[i] = (gchar*)0;
      g_slist_free(names);
    }
  else
    dirnames = (gchar**)0;

  gtk_window_get_size(GTK_WINDOW(file_selector), &gtkFileChooserWidth,
		      &gtkFileChooserHeight);

  gtk_widget_destroy (file_selector);

  return dirnames;
}

/*******************/
/* Local callbacks */
/*******************/
static gboolean onHomePressed(GtkWidget *widget, GdkEventKey *event,
			      gpointer data _U_)
{
  GtkWidget *focus;

  DBG_fprintf(stderr, "Gtk Main: get key pressed.\n");
  if(event->keyval == GDK_KEY_Home && !VISU_UI_MAIN(data)->priv->oneWindow)
    {
      focus = gtk_window_get_focus(GTK_WINDOW(widget));
      if (GTK_IS_EDITABLE(focus))
        return FALSE;
      gtk_window_present(visu_ui_getRenderWindow());
      return TRUE;
    }
  return FALSE;
}
static void onShowMainPanel(VisuUiMain *main, VisuUiRenderingWindow *window _U_)
{
  if (main->priv->actionDialogIsShown)
    gtk_window_present(GTK_WINDOW(main->interactiveDialog));
  else
    gtk_window_present(GTK_WINDOW(main));
}
static void onLoadButtonClicked(VisuUiMain *main, GtkButton *button _U_)
{
  visu_ui_rendering_window_open(VISU_UI_RENDERING_WINDOW(main->renderingWindow),
                                GTK_WINDOW(main));
}
static void onPairsCloseClicked(VisuUiMain *main, GtkButton *button _U_)
{
  hideWindow(GTK_WINDOW(main->pairsDialog));
}
static gboolean onKillPairsDialog(VisuUiMain *main, GdkEvent *event _U_,
				  gpointer data _U_)
{
  hideWindow(GTK_WINDOW(main->pairsDialog));

  return TRUE;
}
static void onPairsButtonClicked(VisuUiMain *main, GtkButton *button _U_)
{
  GtkWidget *wd;

  if (!main->pairsDialog)
    {
      visu_ui_pairs_initBuild(main);
      wd = lookup_widget(main->pairsDialog, "closebutton3");
      g_signal_connect_swapped(G_OBJECT(wd), "clicked",
			       G_CALLBACK(onPairsCloseClicked),
			       (gpointer)main);
      g_signal_connect_swapped(G_OBJECT(main->pairsDialog), "delete-event",
			       G_CALLBACK(onKillPairsDialog),
			       (gpointer)main);
      g_signal_connect_swapped(G_OBJECT(main->pairsDialog), "destroy-event",
			       G_CALLBACK(onKillPairsDialog),
			       (gpointer)main);
    }

  showWindow(GTK_WINDOW(main->pairsDialog));
}
static void onActionsCloseClicked(VisuUiMain *main, GtkButton *button _U_)
{
  hideWindow(GTK_WINDOW(main->interactiveDialog));
  main->priv->actionDialogIsShown = FALSE;
  if (!main->priv->oneWindow)
    showWindow(GTK_WINDOW(main));
}
static gboolean onKillInteractiveDialog(VisuUiMain *main,
					GdkEvent *event _U_, gpointer data _U_)
{
  onActionsCloseClicked(main, (GtkButton*)0);
  

  return TRUE;
}
static void _raiseMouseActionDialog(VisuUiMain *main, VisuUiRenderingWindow *window)
{
  gint posx, posy;

  if (!main->interactiveDialog)
    visu_ui_main_buildInteractiveDialog(main);

  /* Start new pick & observe session. */
  visu_ui_interactive_start(window);

  if (!main->priv->oneWindow)
    {
      gtk_window_get_position(GTK_WINDOW(main), &posx, &posy);
      DBG_fprintf(stderr, "Gtk Main: get command panel position"
		  " (%d,%d).\n", posx, posy);
      hideWindow(GTK_WINDOW(main));
      DBG_fprintf(stderr, "Gtk Main: set observe position (%d,%d).\n", posx, posy);
      gtk_window_move(GTK_WINDOW(main->interactiveDialog), posx, posy);
    }
  showWindow(GTK_WINDOW(main->interactiveDialog));
  main->priv->actionDialogIsShown = TRUE;
}
static void onMouseActionsClicked(VisuUiMain *main, GtkButton *button _U_)
{
  _raiseMouseActionDialog(main, VISU_UI_RENDERING_WINDOW(main->renderingWindow));
}
static void onShowActionDialog(VisuUiMain *main, VisuUiRenderingWindow *window)
{
  _raiseMouseActionDialog(main, window);
}
static void onSaveButtonClicked(VisuUiMain *main _U_, GtkButton *button _U_)
{
  visu_ui_save_initBuild();
}
static void onQuitButtonClicked(VisuUiMain *main, GtkButton *button _U_)
{
  visu_ui_main_quit(main, FALSE);
}
static gboolean onKillAboutDialog(VisuUiMain *main, GdkEvent *event _U_,
				  gpointer data _U_)
{
  hideWindow(GTK_WINDOW(main->aboutDialog));

  return TRUE;
}
static void onAboutButtonClicked(VisuUiMain *main, GtkButton *button _U_)
{
  if (!main->aboutDialog)
    {
      visu_ui_about_initBuild(main);
      g_signal_connect_swapped(G_OBJECT(main->aboutDialog), "delete-event",
			       G_CALLBACK(onKillAboutDialog),
			       (gpointer)main);
      g_signal_connect_swapped(G_OBJECT(main->aboutDialog), "destroy-event",
			       G_CALLBACK(onKillAboutDialog),
			       (gpointer)main);
    }
  showWindow(GTK_WINDOW(main->aboutDialog));
}

static void onDataReady(VisuGlNodeScene *scene, GParamSpec *pspec _U_, gpointer data)
{
  VisuData *dataObj;

  dataObj = visu_gl_node_scene_getData(scene);
  visu_ui_panel_class_setCurrent(dataObj, visu_gl_node_scene_getGlView(scene));
  g_signal_emit(G_OBJECT(data), visu_ui_main_signals[DATA_FOCUSED_SIGNAL],
                0, dataObj);
}
static gboolean onKillMainWindowEvent(GtkWidget *widget _U_, GdkEvent *event _U_,
				      gpointer user_data)
{
  visu_ui_main_quit(VISU_UI_MAIN(user_data), FALSE);
  return TRUE;
}



/*****************/
/* Miscellaneous */
/*****************/

void visu_ui_main_buildInteractiveDialog(VisuUiMain *main)
{
  GtkWidget *wd;

  g_return_if_fail(VISU_IS_UI_MAIN(main) && !main->interactiveDialog);

  visu_ui_interactive_initBuild(main);
  wd = lookup_widget(main->interactiveDialog, "buttonBackToCommandPanel");
  g_signal_connect_swapped(G_OBJECT(wd), "clicked",
			   G_CALLBACK(onActionsCloseClicked),
			   (gpointer)main);
  g_signal_connect_swapped(G_OBJECT(main->interactiveDialog), "delete-event",
			   G_CALLBACK(onKillInteractiveDialog),
			   (gpointer)main);
  g_signal_connect_swapped(G_OBJECT(main->interactiveDialog), "destroy-event",
			   G_CALLBACK(onKillInteractiveDialog),
			   (gpointer)main);
}

/* This method hides the specified window and save its coordinates if
   it is specified by a parameter. */
static void hideWindow(GtkWindow *win)
{
  int *val;

  if (!win)
    return;

  if (my_class->rememberWindowPosition)
    {
      val = (int*)g_hash_table_lookup(my_class->windowPosition, win);
      if (!val)
	{
	  val = g_malloc(sizeof(int) * 2);
	  g_hash_table_insert(my_class->windowPosition, (gpointer)win, (gpointer)val);
	}
      gtk_window_get_position(win, &val[0], &val[1]);
      DBG_fprintf(stderr, "Gtk Main : store position (%d,%d) for window %d.\n", 
		  val[0], val[1], GPOINTER_TO_INT(win));
    }
  gtk_widget_hide(GTK_WIDGET(win));
}

/* This method shows the specified window and try to put it at its
   former position if the good parameter is used. */
static void showWindow(GtkWindow *win)
{
  int *val;

  if (!win)
    return;

  if (my_class->rememberWindowPosition)
    {
      val = (int*)g_hash_table_lookup(my_class->windowPosition, win);
      if (val)
	{
	  gtk_window_move(win, val[0], val[1]);
	  DBG_fprintf(stderr, "Gtk Main : set position (%d,%d) for window %d.\n", 
		      val[0], val[1], GPOINTER_TO_INT(win));
	}
    }
  gtk_window_present(win);
}

void onHideNextTime(GtkToggleButton *button, gpointer data)
{
  char *posNext;
  gchar *path, *bufferR, *pos;
  GString *bufferW, *bufferW2;
  gboolean resOk;
  int lines;
  GIOChannel *file;
  GError *err;
  gsize taille;
  GIOStatus statOK;

  g_return_if_fail(data);
  path = (gchar*)data;
  
  DBG_fprintf(stderr, "Gtk Main : change the warning dialog parameter in file '%s'.\n", path);
  my_class->warningWhenQuit = !gtk_toggle_button_get_active(button);

  /* If no file exists in the given path, we create it. */
  if (!g_file_test(path, G_FILE_TEST_EXISTS))
    {
      err = (GError*)0;
      resOk = visu_config_file_save(VISU_CONFIG_FILE_PARAMETER, path,
                                    &lines, (VisuData*)0, &err);
      if (!resOk)
	{
	  visu_ui_raiseWarningLong(_("Saving a file"), err->message,
				   (GtkWindow*)0);
	  g_error_free(err);
	}
      return;
    }

  /* If a parameter file already exist, we then just change the right line. */
  bufferR = (gchar*)0;
  err = (GError*)0;
  if (!g_file_get_contents(path, &bufferR, &taille, &err))
    {
      visu_ui_raiseWarningLong(_("Saving a file"), err->message, (GtkWindow*)0);
      g_error_free(err);
      return;
    }

  /* We reopen the channel in write acces. */
  err = (GError*)0;
  file = g_io_channel_new_file(path, "w", &err);
  if (err)
    {
      visu_ui_raiseWarningLong(_("Saving a file"), err->message, (GtkWindow*)0);
      g_error_free(err);
      return;
    }

  g_return_if_fail(bufferR);
  bufferW = g_string_new(bufferR);
  g_free(bufferR);
  /* Try to find the flag of the parameter. */
  pos = g_strrstr(bufferW->str, "\n"FLAG_PARAMETER_GTKMAIN_QUIT);
  if (!pos)
    {
      /* We append it at the end of the file. */
      DBG_fprintf(stderr, " | Can't find the option, appending it.\n");
      exportParametersVisuUiMain(bufferW, (VisuData*)0);

      err = (GError*)0;
      statOK = g_io_channel_write_chars(file, bufferW->str, -1,
                                        &taille, &err);
      if (statOK != G_IO_STATUS_NORMAL && err)
	{
	  visu_ui_raiseWarningLong(_("Saving a file"), err->message, (GtkWindow*)0);
	  g_error_free(err);
	}
    }
  else
    {
      DBG_fprintf(stderr, " | ToolOption found, changing its value.\n");
      /* We erase the line and rewrite it. */
      *(pos + 1) = '\0';
      bufferW2 = g_string_new(bufferW->str);
      g_string_append_printf(bufferW2, "%s[gtk]: %i\n", FLAG_PARAMETER_GTKMAIN_QUIT,
			     (int)my_class->warningWhenQuit);
      posNext = strstr(pos + 2, "\n");
      if (posNext)
	g_string_append(bufferW2, posNext + 1);
      
      err = (GError*)0;
      statOK = g_io_channel_write_chars(file, bufferW2->str, -1,
                                        &taille, &err);
      if (err)
	{
	  visu_ui_raiseWarningLong(_("Saving a file"), err->message, (GtkWindow*)0);
	  g_error_free(err);
	}
      g_string_free(bufferW2, TRUE);
    }
  g_io_channel_shutdown(file, TRUE, (GError**)0);
  g_io_channel_unref(file);

  g_string_free(bufferW, TRUE);
}
static void onAddHomedir(GtkButton *button _U_, gpointer quitDialog)
{
  GtkWidget *wd;
  GList *dirs, *tmplst;
  gchar *path;
#if SYSTEM_X11 == 1
#define PERMS (S_IRWXU | S_IRGRP | S_IXGRP)
#endif
#if SYSTEM_WIN32 == 1
#define PERMS 0
#endif

  DBG_fprintf(stderr, "Gtk Main: try to create the local home directory.\n");
#if GLIB_MINOR_VERSION > 7
  if (g_mkdir_with_parents(V_SIM_LOCAL_CONF_DIR, PERMS))
#else
#if SYSTEM_X11 == 1
    if (mkdir(V_SIM_LOCAL_CONF_DIR, PERMS))
#endif
#if SYSTEM_WIN32 == 1
      if (mkdir(V_SIM_LOCAL_CONF_DIR))
#endif
#endif
	/* Failed. */
	visu_ui_raiseWarning(_("I/O"),
			     _("Can't create the directory '$XDG_CONFIG_HOME/v_sim'."),
			     (GtkWindow*)0);
      else
	{
	  /* Succeed hide the warning. */
	  wd = lookup_widget(GTK_WIDGET(quitDialog), "hboxHomedir");
	  gtk_widget_hide(wd);
	  /* Retest the path. */
	  dirs = (GList*)0;
	  dirs = g_list_prepend(dirs, (gpointer)V_SIM_DATA_DIR);
	  dirs = g_list_prepend(dirs, (gpointer)V_SIM_LOCAL_CONF_DIR);
	  tmplst = dirs;

	  path = (gchar*)0;
	  path = visu_config_file_getNextValidPath(VISU_CONFIG_FILE_PARAMETER,
						 W_OK, &tmplst, 0);
	  if (path)
	    {
	      wd = lookup_widget(GTK_WIDGET(quitDialog), "hboxWarning");
	      gtk_widget_hide(wd);
	      wd = lookup_widget(GTK_WIDGET(quitDialog), "checkbuttonHideNextTime");
	      gtk_widget_set_sensitive(wd, TRUE);
	      g_signal_connect(G_OBJECT(wd), "toggled",
			       G_CALLBACK(onHideNextTime), (gpointer)path);
	    }
	  g_list_free(dirs);
	}
}

static void freeAllAndStop(VisuUiMain *main)
{
  DBG_fprintf(stderr, "Gtk Main: kill command panel.\n");
  gtk_widget_destroy(GTK_WIDGET(main));

  visu_ui_rendering_window_class_finalize();
  g_hash_table_destroy(my_class->windowPosition);

  DBG_fprintf(stderr, "Gtk Main: stopping GTK and that's all.\n");
  gtk_main_quit();
}

void visu_ui_main_quit(VisuUiMain *main, gboolean force)
{
  GtkWidget *quitDialog, *wd;
  GList *dirs, *tmplst;
  gchar *path;

  if (force || !my_class->warningWhenQuit)
    {
      freeAllAndStop(main);
      return;
    }

  quitDialog = create_quitDialog();
  gtk_window_set_transient_for(GTK_WINDOW(quitDialog), GTK_WINDOW(main));
  
  /* Try to find installDir/v_sim.par or $XDG_CONFIG_HOME/v_sim/v_sim.par
     that is writable to store the preference of the hiding
     mode of the dialog. */
  dirs = (GList*)0;
  dirs = g_list_prepend(dirs, (gpointer)V_SIM_DATA_DIR);
  dirs = g_list_prepend(dirs, (gpointer)V_SIM_LOCAL_CONF_DIR);
  tmplst = dirs;

  path = (gchar*)0;
  path = visu_config_file_getNextValidPath(VISU_CONFIG_FILE_PARAMETER, W_OK, &tmplst, 0);
  if (!path)
    {
      wd = lookup_widget(quitDialog, "hboxWarning");
      gtk_widget_show(wd);
    }
  g_list_free(dirs);

  /* Attach a create the homedir method to the button. */
  wd = lookup_widget(quitDialog, "buttonAddHomedir");
  g_signal_connect(G_OBJECT(wd), "clicked",
		   G_CALLBACK(onAddHomedir), (gpointer)quitDialog);
  /* Show the warning if the homedir is not existing and no path was found. */
  if (!g_file_test(V_SIM_LOCAL_CONF_DIR, G_FILE_TEST_IS_DIR) && !path)
    {
      wd = lookup_widget(quitDialog, "hboxHomedir");
      gtk_widget_show(wd);
    }

  /* Attach a modify the parameter to the checkbox. */
  wd = lookup_widget(quitDialog, "checkbuttonHideNextTime");
  if (!path)
    gtk_widget_set_sensitive(wd, FALSE);
  else
    g_signal_connect(G_OBJECT(wd), "toggled",
		     G_CALLBACK(onHideNextTime), (gpointer)path);
  
  if (gtk_dialog_run(GTK_DIALOG(quitDialog)) == GTK_RESPONSE_OK)
    freeAllAndStop(main);
  else
    gtk_widget_destroy(quitDialog);
}

static gboolean readMainPanelStatus(VisuConfigFileEntry *entry _U_, gchar **lines, int nbLines, int position,
                                    GError **error)
{
  gchar **tokens;
  VisuUiPanel *toolpanel;
  char *pt;

  g_return_val_if_fail(nbLines == 1, FALSE);

  if (!tool_config_file_readString(lines[0], position, &tokens, 2, TRUE, error))
    return FALSE;
  toolpanel = visu_ui_panel_class_getPanelById(tokens[0]);
  if (toolpanel)
    {
      pt = strchr(tokens[1], '\n');
      if (pt)
        *pt = ' ';
      visu_ui_panel_setContainerId(toolpanel, g_strchomp(tokens[1]));
    }

  g_strfreev(tokens);
  return TRUE;
}
static gboolean readMainDock(VisuConfigFileEntry *entry _U_, gchar **lines, int nbLines, int position,
			     GError **error)
{
  int res;
  gchar **tokens, *values;
  gboolean visible;
  int x, y, width, height;
  VisuUiDockWindow *dock;

  g_return_val_if_fail(nbLines == 1, FALSE);

  tokens = g_strsplit(g_strchug(lines[0]), " ", 4);
  if (!tokens[0] || !tokens[1] || !tokens[2] || !tokens[3])
    {
      *error = g_error_new(TOOL_CONFIG_FILE_ERROR, TOOL_CONFIG_FILE_ERROR_VALUE,
			   _("Parse error at line %d: awaited "
			     "'id visible pos size'.\n"),
			   position);
      g_strfreev(tokens);
      return FALSE;
    }
  values = g_strjoin(" ", tokens[0], tokens[1], tokens[2], NULL);
  res = sscanf(values, "%d %dx%d %dx%d", (int*)&visible, &x, &y, &width, &height);
  if (res != 5)
    {
      *error = g_error_new(TOOL_CONFIG_FILE_ERROR, TOOL_CONFIG_FILE_ERROR_VALUE,
			   _("Parse error at line %d: can't read dock"
			     " characteristic values from '%s'.\n"),
			   position, values);
      g_strfreev(tokens);
      g_free(values);
      return FALSE;
    }
  g_free(values);

  /* Get the dock window associated to id, or create a new one. */
  dock = visu_ui_panel_class_getDockById(g_strchomp(tokens[3]));
  visu_ui_dock_window_setSize(dock, (guint)width, (guint)height);
  visu_ui_dock_window_setPosition(dock, (guint)x, (guint)y);
  visu_ui_dock_window_setVisibility(dock, visible);

  g_strfreev(tokens);

  return TRUE;
}
static void exportParametersVisuUiMain(GString *data,
                                       VisuData* dataObj _U_)
{
  GList *tmplst, *panelLst, *dockLst;
  gint x, y, width, height;
  gboolean visilibity;
  gchar *id;

  g_string_append_printf(data, "# %s\n", DESC_PARAMETER_GTKMAIN_QUIT);
  g_string_append_printf(data, "%s[gtk]: %i\n\n", FLAG_PARAMETER_GTKMAIN_QUIT,
			 (int)my_class->warningWhenQuit);

  /* Write the panel list. */
  panelLst = visu_ui_panel_class_getAllPanels();
  if (panelLst)
    {
      g_string_append_printf(data, "# %s\n", DESC_PARAMETER_GTKMAIN_PANEL);
      for (tmplst = panelLst; tmplst; tmplst = g_list_next(tmplst))
	g_string_append_printf(data, "%s[gtk]: %s %s\n", FLAG_PARAMETER_GTKMAIN_PANEL,
			       visu_ui_panel_getId(VISU_UI_PANEL(tmplst->data)),
			       visu_ui_panel_getContainerId(VISU_UI_PANEL(tmplst->data)));
      g_string_append_printf(data, "\n");
      g_list_free(panelLst);
    }

  /* Write the panel list. */
  dockLst = visu_ui_panel_class_getAllWindows();
  if (dockLst)
    {
      g_string_append_printf(data, "# %s\n", DESC_PARAMETER_GTKMAIN_DOCK);
      for (tmplst = dockLst; tmplst; tmplst = g_list_next(tmplst))
	{ 
	  visu_ui_dock_window_getCharacteristics
	    ((VisuUiDockWindow*)(tmplst->data), &id,
	     &visilibity, &x, &y, &width, &height);
	  g_string_append_printf(data, "%s[gtk]: %d %dx%d %dx%d %s\n",
				 FLAG_PARAMETER_GTKMAIN_DOCK,
				 (int)visilibity, x, y, width, height, id);
	}
      g_string_append_printf(data, "\n");
      g_list_free(dockLst);
    }
}
gboolean visu_ui_main_initPanels(gpointer data)
{
  GList *pnt;

  DBG_fprintf(stderr, "Gtk Main: initialise panels.\n");
  for (pnt = visu_plugins_getListLoaded(); pnt; pnt = g_list_next(pnt))
    visu_plugin_initGtk((VisuPlugin*)pnt->data);

  visu_ui_panel_browser_setCurrentDirectory(visu_ui_main_getLastOpenDirectory(VISU_UI_MAIN(data)));
  DBG_fprintf(stderr, " | done.\n");
  return FALSE;
}
gboolean visu_ui_main_runCommandLine(gpointer data)
{
  VisuUiMain *self;
  VisuGlNodeScene *scene;
  GError *error;

  self = VISU_UI_MAIN(data);
  scene = visu_ui_rendering_window_getGlScene(VISU_UI_RENDERING_WINDOW(self->renderingWindow));
  if (!visu_gl_node_scene_getData(scene))
    return G_SOURCE_REMOVE;
  
  error = (GError*)0;
  if (!visu_gl_node_scene_applyCLI(scene, &error))
    {
      visu_ui_raiseWarning(_("Command line actions"),
                           error ? error->message : _("Unknown error"),
                           GTK_WINDOW(data));
      g_clear_error(&error);
    }
  return G_SOURCE_REMOVE;
}

/*******************/
/* Class routines. */
/*******************/
/**
 * visu_ui_main_class_getCurrentPanel:
 *
 * This routine can be used to get the command panel, everywhere from
 * V_Sim.
 *
 * Returns: (transfer none): the command Panel.
 */
VisuUiMain* visu_ui_main_class_getCurrentPanel()
{
  return currentVisuUiMain;
}
/**
 * visu_ui_main_class_setCurrentPanel:
 * @main: a command panel.
 *
 * After having created the command panel with visu_ui_main_new(), use this
 * routine to declare it as the current command panel.
 */
void visu_ui_main_class_setCurrentPanel(VisuUiMain *main)
{
  g_return_if_fail(VISU_IS_UI_MAIN(main));
  currentVisuUiMain = main;
}

void visu_ui_main_class_setRememberPosition(gboolean val)
{
  g_return_if_fail(my_class);

  DBG_fprintf(stderr, "Gtk Main: set the remember parameter to %d.\n", val);
  my_class->rememberWindowPosition = val;
}
gboolean visu_ui_main_class_getRememberPosition()
{
  g_return_val_if_fail(my_class, PARAMETER_GTKMAIN_REMEMBER_DEFAULT);
  return my_class->rememberWindowPosition;
}

/**
 * visu_ui_main_class_createMain:
 * @panel: a location for a #VisuUiMain panel ;
 * @renderWindow: a location for a #GtkWindow ;
 * @renderArea: a location for a #GtkWidget.
 *
 * A convenience routine to create a command panel, a rendering window
 * and links them together.
 */
void visu_ui_main_class_createMain(GtkWindow **panel,
                                   GtkWindow **renderWindow, GtkWidget **renderArea)
{
  gboolean oneWindow;

  oneWindow = (!strcmp(commandLineGet_windowMode(), "oneWindow"));

  *panel = GTK_WINDOW(visu_ui_main_new(oneWindow));
  *renderArea = GTK_WIDGET(VISU_UI_MAIN(*panel)->renderingWindow);
  DBG_fprintf(stderr, "Gtk Main: command panel -> %p.\n",
              (gpointer)(*panel));
  if (!oneWindow)
    {
      *renderWindow = GTK_WINDOW(visu_ui_buildRenderingWindow(VISU_UI_RENDERING_WINDOW(*renderArea)));
      g_signal_connect(G_OBJECT(*renderWindow), "delete-event",
		       G_CALLBACK(onKillMainWindowEvent), (gpointer)(*panel));
      g_signal_connect(G_OBJECT(*renderWindow), "destroy-event",
		       G_CALLBACK(onKillMainWindowEvent), (gpointer)(*panel));
      gtk_widget_show(GTK_WIDGET(*renderWindow));
    }
  else
    *renderWindow = *panel;
  g_object_bind_property(*renderArea, "label", *renderWindow, "title",
                         G_BINDING_SYNC_CREATE);

  visu_ui_interactive_pick_init();
  g_type_class_ref(visu_ui_shade_combobox_get_type());

  gtk_widget_show(GTK_WIDGET(*panel));

  return;
}
/**
 * visu_ui_main_class_getDefaultRendering:
 *
 * Get the rendering window of V_Sim.
 *
 * Returns: (transfer none): the rendering window.
 */
VisuUiRenderingWindow* visu_ui_main_class_getDefaultRendering()
{
  g_return_val_if_fail(currentVisuUiMain, (VisuUiRenderingWindow*)0);

  DBG_fprintf(stderr, "Gtk Main: access the rendering window %p.\n",
	      (gpointer)currentVisuUiMain->renderingWindow);
  return VISU_UI_RENDERING_WINDOW(currentVisuUiMain->renderingWindow);
}
